mirror of
https://github.com/humhub/humhub.git
synced 2025-01-17 14:18:27 +01:00
Rework modules section (#5476)
* Rework modules section * Rework modules section * Filter modules * Menu controls for module cards * Display only modules * Filter online modules by category * Filter installed modules by category * Filter modules by tags * Display module status * Reorder tags on module filters * Display HumHub update info on modules list * Menu controls on online modules * Display available updates for modules * Remove not used code of old module views * Link to settings from modules page * Redesign modules for user and space * Fix user modules layout on fluid themes * Animate module updating * Button to update all modules * Update style for modules list on space creating * Fixed errors without available Marketplace module * Sort enabled modules before disabled * Use MarketplaceModule::$enabled on init modules list * Update method getEnabledMarketplaceModule() * Use MarketplaceModule::$enabled on init modules list * Move module online info methods into separate behavior * Update code of modules list * Rename 'humhub.directory.js' to 'humhub.cards.js' * Factorize online module data loading * Move purchase licence key to new modules layout * Align center update info * Fix filter modules * Fix filter modules by tags "Installed"/"Not Installed" * Update styles of modules settings icon * New online module status "isPartner" * Keep single active filter tag on modules list * Hide the not installed deprecated modules * Update layout of module status label * Space above filter "Tags" * Detect module status "Professional Edition" as top priority * Hide installed or not installed modules on single filter tag * Update styles for upgrade humhub info on modules list * Tooltip for button "Professional Edition" * Fix "Buy" link * Restyle no modules results * Update no modules results * Minor changes * Changed Updater link Co-authored-by: Lucas Bartholemy <lucas@bartholemy.com> Co-authored-by: Lucas Bartholemy <luke-@users.noreply.github.com>
This commit is contained in:
parent
d1a387137c
commit
af12a33d9d
@ -2,10 +2,11 @@
|
|||||||
------------------------------------------
|
------------------------------------------
|
||||||
- Fix #5434: Hide disabled next/prev buttons on guide first/last steps
|
- Fix #5434: Hide disabled next/prev buttons on guide first/last steps
|
||||||
- Fix #5456: `canImpersonate` only possible for SystemAdmins
|
- Fix #5456: `canImpersonate` only possible for SystemAdmins
|
||||||
|
- Enh #5476: Rework modules administration section
|
||||||
- Enh #5472: New interface `TabbedFormModel` for activate first tab with error input
|
- Enh #5472: New interface `TabbedFormModel` for activate first tab with error input
|
||||||
- Enh #5224: Add reply-to email in the settings
|
- Enh #5224: Add reply-to email in the settings
|
||||||
- Enh #5471: On the pending approval page, add grouped actions and custom columns
|
- Enh #5471: On the pending approval page, add grouped actions and custom columns
|
||||||
- Enh #5490: Display confirmation message before display embedded content
|
- Enh #5490: Display confirmation message before display embedded content
|
||||||
- Enh #5258: Display who invited the user on the Approval page
|
- Enh #5258: Display who invited the user on the Approval page
|
||||||
- Enh #4890: Allow to define actions in a controller which should not be intercepted by other actions
|
- Enh #4890: Allow to define actions in a controller which should not be intercepted by other actions
|
||||||
- Enh #5510: oEmbed support for other social networks, redesign of oEmbed settings pages
|
- Enh #5510: oEmbed support for other social networks, redesign of oEmbed settings pages
|
||||||
|
@ -10,13 +10,13 @@ namespace humhub\assets;
|
|||||||
use humhub\components\assets\WebStaticAssetBundle;
|
use humhub\components\assets\WebStaticAssetBundle;
|
||||||
use yii\web\View;
|
use yii\web\View;
|
||||||
|
|
||||||
class DirectoryAsset extends WebStaticAssetBundle
|
class CardsAsset extends WebStaticAssetBundle
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public $js = [
|
public $js = [
|
||||||
'js/humhub/humhub.directory.js',
|
'js/humhub/humhub.cards.js',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
@ -8,21 +8,23 @@
|
|||||||
|
|
||||||
namespace humhub\components;
|
namespace humhub\components;
|
||||||
|
|
||||||
use humhub\modules\activity\components\BaseActivity;
|
|
||||||
use humhub\modules\activity\models\Activity;
|
|
||||||
use Yii;
|
|
||||||
use yii\helpers\Json;
|
|
||||||
use humhub\models\Setting;
|
use humhub\models\Setting;
|
||||||
|
use humhub\modules\activity\components\BaseActivity;
|
||||||
|
use humhub\modules\content\models\ContentContainerSetting;
|
||||||
use humhub\modules\file\libs\FileHelper;
|
use humhub\modules\file\libs\FileHelper;
|
||||||
use humhub\modules\notification\components\BaseNotification;
|
use humhub\modules\notification\components\BaseNotification;
|
||||||
use humhub\modules\content\models\ContentContainerSetting;
|
use Yii;
|
||||||
|
use yii\helpers\Json;
|
||||||
use yii\web\AssetBundle;
|
use yii\web\AssetBundle;
|
||||||
use yii\web\HttpException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base Class for Modules / Extensions
|
* Base Class for Modules / Extensions
|
||||||
*
|
*
|
||||||
|
* @property-read string $name
|
||||||
|
* @property-read string $description
|
||||||
|
* @property-read bool $isActivated
|
||||||
* @property SettingsManager $settings
|
* @property SettingsManager $settings
|
||||||
|
* @mixin OnlineModule
|
||||||
* @author luke
|
* @author luke
|
||||||
*/
|
*/
|
||||||
class Module extends \yii\base\Module
|
class Module extends \yii\base\Module
|
||||||
@ -204,6 +206,16 @@ class Module extends \yii\base\Module
|
|||||||
return $this->getBasePath() . '/' . $this->resourcesPath;
|
return $this->getBasePath() . '/' . $this->resourcesPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check this module is activated
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getIsActivated(): bool
|
||||||
|
{
|
||||||
|
return (bool) Yii::$app->hasModule($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables this module
|
* Enables this module
|
||||||
*
|
*
|
||||||
|
@ -12,6 +12,8 @@ use humhub\components\bootstrap\ModuleAutoLoader;
|
|||||||
use humhub\components\console\Application as ConsoleApplication;
|
use humhub\components\console\Application as ConsoleApplication;
|
||||||
use humhub\libs\BaseSettingsManager;
|
use humhub\libs\BaseSettingsManager;
|
||||||
use humhub\models\ModuleEnabled;
|
use humhub\models\ModuleEnabled;
|
||||||
|
use humhub\modules\admin\events\ModulesEvent;
|
||||||
|
use humhub\modules\marketplace\Module as ModuleMarketplace;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\base\Component;
|
use yii\base\Component;
|
||||||
use yii\base\Event;
|
use yii\base\Event;
|
||||||
@ -51,6 +53,12 @@ class ModuleManager extends Component
|
|||||||
*/
|
*/
|
||||||
const EVENT_AFTER_MODULE_DISABLE = 'afterModuleDisabled';
|
const EVENT_AFTER_MODULE_DISABLE = 'afterModuleDisabled';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @event triggered after filter modules
|
||||||
|
* @since 1.11
|
||||||
|
*/
|
||||||
|
const EVENT_AFTER_FILTER_MODULES = 'afterFilterModules';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a backup on module folder deletion
|
* Create a backup on module folder deletion
|
||||||
*
|
*
|
||||||
@ -239,25 +247,25 @@ class ModuleManager extends Component
|
|||||||
*/
|
*/
|
||||||
public function getModules($options = [])
|
public function getModules($options = [])
|
||||||
{
|
{
|
||||||
|
$options = array_merge([
|
||||||
|
'includeCoreModules' => false,
|
||||||
|
'enabled' => false,
|
||||||
|
'returnClass' => false,
|
||||||
|
], $options);
|
||||||
|
|
||||||
$modules = [];
|
$modules = [];
|
||||||
|
|
||||||
foreach ($this->modules as $id => $class) {
|
foreach ($this->modules as $id => $class) {
|
||||||
|
if (!$options['includeCoreModules'] && in_array($class, $this->coreModules)) {
|
||||||
// Skip core modules
|
// Skip core modules
|
||||||
if (!isset($options['includeCoreModules']) || $options['includeCoreModules'] === false) {
|
continue;
|
||||||
if (in_array($class, $this->coreModules)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($options['enabled'] && !in_array($class, $this->coreModules) && !in_array($id, $this->enabledModules)) {
|
||||||
if (isset($options['enabled']) && $options['enabled'] === true) {
|
// Skip disabled modules
|
||||||
if (!in_array($class, $this->coreModules) && !in_array($id, $this->enabledModules)) {
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['returnClass']) && $options['returnClass']) {
|
if ($options['returnClass']) {
|
||||||
$modules[$id] = $class;
|
$modules[$id] = $class;
|
||||||
} else {
|
} else {
|
||||||
$module = $this->getModule($id);
|
$module = $this->getModule($id);
|
||||||
@ -270,6 +278,70 @@ class ModuleManager extends Component
|
|||||||
return $modules;
|
return $modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter modules by keyword and by additional filters from module event
|
||||||
|
*
|
||||||
|
* @param Module[] $modules
|
||||||
|
* @param array $filters
|
||||||
|
* @return Module[]
|
||||||
|
*/
|
||||||
|
public function filterModules(array $modules, $filters = []): array
|
||||||
|
{
|
||||||
|
$filters = array_merge([
|
||||||
|
'keyword' => null,
|
||||||
|
], $filters);
|
||||||
|
|
||||||
|
$modules = $this->filterModulesByKeyword($modules, $filters['keyword']);
|
||||||
|
|
||||||
|
$modulesEvent = new ModulesEvent(['modules' => $modules]);
|
||||||
|
$this->trigger(static::EVENT_AFTER_FILTER_MODULES, $modulesEvent);
|
||||||
|
|
||||||
|
return $modulesEvent->modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter modules by keyword
|
||||||
|
*
|
||||||
|
* @param Module[] $modules
|
||||||
|
* @param null|string $keyword
|
||||||
|
* @return Module[]
|
||||||
|
*/
|
||||||
|
public function filterModulesByKeyword(array $modules, $keyword = null): array
|
||||||
|
{
|
||||||
|
if ($keyword === null) {
|
||||||
|
$keyword = Yii::$app->request->get('keyword', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_scalar($keyword) || $keyword === '') {
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($modules as $id => $module) {
|
||||||
|
/* @var Module $module */
|
||||||
|
$searchFields = [$id];
|
||||||
|
if (isset($module->name)) {
|
||||||
|
$searchFields[] = $module->name;
|
||||||
|
}
|
||||||
|
if (isset($module->description)) {
|
||||||
|
$searchFields[] = $module->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
$keywordFound = false;
|
||||||
|
foreach ($searchFields as $searchField) {
|
||||||
|
if (stripos($searchField, $keyword) !== false) {
|
||||||
|
$keywordFound = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$keywordFound) {
|
||||||
|
unset($modules[$id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all enabled modules and supportes further options as [[getModules()]].
|
* Returns all enabled modules and supportes further options as [[getModules()]].
|
||||||
*
|
*
|
||||||
@ -359,8 +431,12 @@ class ModuleManager extends Component
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check is in dynamic/marketplace module folder
|
// Check is in dynamic/marketplace module folder
|
||||||
if (strpos($module->getBasePath(), Yii::getAlias(Yii::$app->getModule('marketplace')->modulesPath)) !== false) {
|
/** @var ModuleMarketplace $marketplaceModule */
|
||||||
return true;
|
$marketplaceModule = Yii::$app->getModule('marketplace');
|
||||||
|
if ($marketplaceModule !== null) {
|
||||||
|
if (strpos($module->getBasePath(), Yii::getAlias($marketplaceModule->modulesPath)) !== false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
142
protected/humhub/components/OnlineModule.php
Normal file
142
protected/humhub/components/OnlineModule.php
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\components;
|
||||||
|
|
||||||
|
use humhub\modules\marketplace\models\Licence;
|
||||||
|
use humhub\modules\marketplace\models\Module as ModelModule;
|
||||||
|
use humhub\modules\marketplace\Module as MarketplaceModule;
|
||||||
|
use Yii;
|
||||||
|
use yii\base\Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Online Module class for load module date from marketplace
|
||||||
|
*
|
||||||
|
* @property-read bool $isInstalled
|
||||||
|
* @property-read bool $isProOnly
|
||||||
|
* @property-read bool $isFeatured
|
||||||
|
* @property-read bool $isThirdParty
|
||||||
|
* @property-read bool $isPartner
|
||||||
|
* @property-read bool $isDeprecated
|
||||||
|
* @property-read array $categories
|
||||||
|
*
|
||||||
|
* @author Lucas Bartholemy <lucas@bartholemy.com>
|
||||||
|
* @since 1.11
|
||||||
|
*/
|
||||||
|
class OnlineModule extends Component
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Module
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array the cached info loaded from online
|
||||||
|
*/
|
||||||
|
private $_onlineInfo = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get online info of the Module
|
||||||
|
*
|
||||||
|
* @param string|null $field Null - to return all fields, String - to return a value of the requested field:
|
||||||
|
* - id
|
||||||
|
* - name
|
||||||
|
* - description
|
||||||
|
* - useCases
|
||||||
|
* - featured
|
||||||
|
* - showDisclaimer
|
||||||
|
* - isThirdParty
|
||||||
|
* - isCommunity
|
||||||
|
* - isPartner
|
||||||
|
* - isDeprecated
|
||||||
|
* - latestVersion
|
||||||
|
* - moduleImageUrl
|
||||||
|
* - marketplaceUrl
|
||||||
|
* - latestCompatibleVersion
|
||||||
|
* - purchased
|
||||||
|
* - price_eur
|
||||||
|
* - price_request_quote
|
||||||
|
* - checkoutUrl
|
||||||
|
* - professional_only
|
||||||
|
* - categories
|
||||||
|
* @return array|null|string
|
||||||
|
*/
|
||||||
|
public function info(?string $field = null)
|
||||||
|
{
|
||||||
|
if ($this->_onlineInfo === null) {
|
||||||
|
/* @var MarketplaceModule $marketplaceModule */
|
||||||
|
$marketplaceModule = Yii::$app->getModule('marketplace');
|
||||||
|
if (!($marketplaceModule instanceof MarketplaceModule && $marketplaceModule->enabled)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->module instanceof ModelModule) {
|
||||||
|
$this->_onlineInfo = (array)$this->module;
|
||||||
|
} else {
|
||||||
|
$onlineModules = $marketplaceModule->onlineModuleManager->getModules();
|
||||||
|
$this->_onlineInfo = isset($onlineModules[$this->module->id]) ? $onlineModules[$this->module->id] : [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($field === null) {
|
||||||
|
return $this->_onlineInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_onlineInfo[$field] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsInstalled(): bool
|
||||||
|
{
|
||||||
|
return Yii::$app->moduleManager->hasModule($this->module->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isProOnly(): bool
|
||||||
|
{
|
||||||
|
if (empty($this->info('professional_only'))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var MarketplaceModule */
|
||||||
|
$marketplaceModule = Yii::$app->getModule('marketplace');
|
||||||
|
if (!($marketplaceModule instanceof MarketplaceModule && $marketplaceModule->enabled)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $marketplaceModule->licence->type !== Licence::LICENCE_TYPE_PRO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsProOnly(): bool
|
||||||
|
{
|
||||||
|
return $this->isProOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCategories(): array
|
||||||
|
{
|
||||||
|
$onlineInfo = $this->info();
|
||||||
|
return $onlineInfo['categories'] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsFeatured(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->info('featured');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsThirdParty(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->info('isThirdParty');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsPartner(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->info('isPartner');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsDeprecated(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->info('isDeprecated');
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
/**
|
/**
|
||||||
* This file is generated by the "yii asset" command.
|
* This file is generated by the "yii asset" command.
|
||||||
* DO NOT MODIFY THIS FILE DIRECTLY.
|
* DO NOT MODIFY THIS FILE DIRECTLY.
|
||||||
* @version 2021-09-16 07:53:30
|
* @version 2021-12-22 09:17:29
|
||||||
*/
|
*/
|
||||||
return [
|
return [
|
||||||
'app' => [
|
'app' => [
|
||||||
@ -393,6 +393,14 @@ return [
|
|||||||
'defer',
|
'defer',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
'humhub\\assets\\JqueryCookieAsset' => [
|
||||||
|
'sourcePath' => null,
|
||||||
|
'js' => [],
|
||||||
|
'css' => [],
|
||||||
|
'depends' => [
|
||||||
|
'defer',
|
||||||
|
],
|
||||||
|
],
|
||||||
'humhub\\modules\\user\\assets\\UserAsset' => [
|
'humhub\\modules\\user\\assets\\UserAsset' => [
|
||||||
'sourcePath' => null,
|
'sourcePath' => null,
|
||||||
'js' => [],
|
'js' => [],
|
||||||
|
26
protected/humhub/modules/admin/assets/ModuleAsset.php
Normal file
26
protected/humhub/modules/admin/assets/ModuleAsset.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\admin\assets;
|
||||||
|
|
||||||
|
use humhub\components\assets\AssetBundle;
|
||||||
|
|
||||||
|
class ModuleAsset extends AssetBundle
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public $sourcePath = '@admin/resources';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public $css = [
|
||||||
|
'css/modules.css'
|
||||||
|
];
|
||||||
|
}
|
@ -11,6 +11,7 @@ namespace humhub\modules\admin\controllers;
|
|||||||
use humhub\components\Module;
|
use humhub\components\Module;
|
||||||
use humhub\modules\admin\components\Controller;
|
use humhub\modules\admin\components\Controller;
|
||||||
use humhub\modules\admin\models\forms\ModuleSetAsDefaultForm;
|
use humhub\modules\admin\models\forms\ModuleSetAsDefaultForm;
|
||||||
|
use humhub\modules\admin\permissions\ManageModules;
|
||||||
use humhub\modules\content\components\ContentContainerModule;
|
use humhub\modules\content\components\ContentContainerModule;
|
||||||
use humhub\modules\content\components\ContentContainerModuleManager;
|
use humhub\modules\content\components\ContentContainerModuleManager;
|
||||||
use humhub\modules\space\models\Space;
|
use humhub\modules\space\models\Space;
|
||||||
@ -27,6 +28,11 @@ use yii\web\HttpException;
|
|||||||
class ModuleController extends Controller
|
class ModuleController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public $subLayout = '@admin/views/layouts/module';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
@ -38,7 +44,6 @@ class ModuleController extends Controller
|
|||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
$this->appendPageTitle(Yii::t('AdminModule.base', 'Modules'));
|
$this->appendPageTitle(Yii::t('AdminModule.base', 'Modules'));
|
||||||
$this->subLayout = '@admin/views/layouts/module';
|
|
||||||
|
|
||||||
return parent::init();
|
return parent::init();
|
||||||
}
|
}
|
||||||
@ -49,7 +54,7 @@ class ModuleController extends Controller
|
|||||||
public function getAccessRules()
|
public function getAccessRules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['permissions' => \humhub\modules\admin\permissions\ManageModules::class]
|
['permissions' => ManageModules::class]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,53 +64,9 @@ class ModuleController extends Controller
|
|||||||
return $this->redirect(['/admin/module/list']);
|
return $this->redirect(['/admin/module/list']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function actionList()
|
public function actionList()
|
||||||
{
|
{
|
||||||
$installedModules = Yii::$app->moduleManager->getModules();
|
return $this->render('list');
|
||||||
|
|
||||||
return $this->render('list', [
|
|
||||||
'installedModules' => $installedModules,
|
|
||||||
'deprecatedModuleIds' => $this->getDeprecatedModules(),
|
|
||||||
'marketplaceUrls' => $this->getMarketplaceUrls()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function getMarketplaceUrls()
|
|
||||||
{
|
|
||||||
$marketplaceUrls = [];
|
|
||||||
|
|
||||||
if (Yii::$app->hasModule('marketplace')) {
|
|
||||||
try {
|
|
||||||
foreach (Yii::$app->getModule('marketplace')->onlineModuleManager->getModules() as $id => $module) {
|
|
||||||
if (!empty($module['marketplaceUrl'])) {
|
|
||||||
$marketplaceUrls[$id] = $module['marketplaceUrl'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Exception $ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $marketplaceUrls;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function getDeprecatedModules()
|
|
||||||
{
|
|
||||||
$deprecatedModuleIds = [];
|
|
||||||
if (Yii::$app->hasModule('marketplace')) {
|
|
||||||
try {
|
|
||||||
foreach (Yii::$app->getModule('marketplace')->onlineModuleManager->getModules() as $id => $module) {
|
|
||||||
if (!empty($module['isDeprecated'])) {
|
|
||||||
$deprecatedModuleIds[] = $id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Exception $ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $deprecatedModuleIds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
25
protected/humhub/modules/admin/events/ModulesEvent.php
Normal file
25
protected/humhub/modules/admin/events/ModulesEvent.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\admin\events;
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use yii\base\Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event is used when modules is listed and filtered
|
||||||
|
*
|
||||||
|
* @author luke
|
||||||
|
* @since 1.11
|
||||||
|
*/
|
||||||
|
class ModulesEvent extends Event
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Module[]|array
|
||||||
|
*/
|
||||||
|
public $modules;
|
||||||
|
}
|
1
protected/humhub/modules/admin/resources/css/modules.css
Normal file
1
protected/humhub/modules/admin/resources/css/modules.css
Normal file
@ -0,0 +1 @@
|
|||||||
|
.container-modules .modules-type{font-size:16px;font-weight:bold;color:#000;margin:70px 0 40px}.container-modules .row.cards{margin-top:40px}.container-modules .card-module .card-header{position:relative}.container-modules .card-module .card-body{padding-top:8px;font-size:13px;color:#6C787E}.container-modules .card-module .card-body>div{padding-bottom:8px}.container-modules .card-module .card-body>div:last-child{padding-bottom:0}.container-modules .card-module .card-title{color:#000}.container-modules .card-module .card-footer{padding-bottom:14px}.container-modules .card-module .card-footer a.btn{float:none}.container-modules .card-module .card-footer.text-right a.btn{margin-left:8px;margin-right:0}.container-modules .card-module .card-footer.text-right a.btn:first-child{margin-left:0}.container-modules .module-settings-link{float:right;color:#02A1B1;font-size:22px;line-height:20px;margin:2px}.container-content-modules{width:100%;padding:0 18px 5px 5px}.container-content-modules h4{font-size:16px;color:#000}.container-content-modules .card{width:100%;padding-right:3px}.container-content-modules .card .card-panel{margin-top:3px}@media (min-width:460px){.container-content-modules .card{width:50%}}@media (min-width:656px){.container-content-modules .card{width:33.33333333%}}@media (min-width:768px){.container-content-modules{padding:0 12px 5px 0}}@media (min-width:1200px){.container-content-modules .card{width:25%}}.container-create-space-modules{width:100%;padding:0}.container-create-space-modules .card .card-panel{background:#F5F5F5}/*# sourceMappingURL=modules.css.map */
|
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["modules.less"],"names":[],"mappings":"AAAA,kBACI,eACI,cAAA,CACA,gBAAA,CACA,UAAA,CACA,mBALR,kBAOI,KAAI,OACA,gBARR,kBAUI,aACI,cACI,kBAZZ,kBAUI,aAII,YACI,eAAA,CACA,cAAA,CACA,cAjBZ,kBAUI,aAII,WAII,KACI,mBACA,kBAVZ,aAII,WAII,IAEK,YACG,iBArBpB,kBAUI,aAeI,aACI,WA1BZ,kBAUI,aAkBI,cACI,oBA7BZ,kBAUI,aAkBI,aAEI,EAAC,KACG,WAEJ,kBAvBR,aAkBI,aAKK,WACG,EAAC,KACG,eAAA,CACA,eACA,kBA3BhB,aAkBI,aAKK,WACG,EAAC,IAGI,aACG,cAtCxB,kBA4CI,uBACI,WAAA,CACA,aAAA,CACA,cAAA,CACA,gBAAA,CACA,WAIR,2BACI,UAAA,CACA,uBAFJ,0BAGI,IACI,cAAA,CACA,WALR,0BAOI,OACI,UAAA,CACA,kBATR,0BAOI,MAGI,aACI,eAGR,QAA0B,iBAA1B,0BACI,OACI,WAGR,QAA0B,iBAA1B,0BACI,OACI,oBAGR,QAA0B,iBAA1B,2BACI,sBAEJ,QAA2B,kBAA3B,0BACI,OACI,WAKZ,gCACI,UAAA,CACA,UAFJ,+BAGI,MACI,aACI","file":"modules.css"}
|
96
protected/humhub/modules/admin/resources/css/modules.less
Normal file
96
protected/humhub/modules/admin/resources/css/modules.less
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
.container-modules {
|
||||||
|
.modules-type {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #000;
|
||||||
|
margin: 70px 0 40px;
|
||||||
|
}
|
||||||
|
.row.cards {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
.card-module {
|
||||||
|
.card-header {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.card-body {
|
||||||
|
padding-top: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6C787E;
|
||||||
|
> div {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
&:last-child {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.card-title {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.card-footer {
|
||||||
|
padding-bottom: 14px;
|
||||||
|
a.btn {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
&.text-right {
|
||||||
|
a.btn {
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-right: 0;
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.module-settings-link {
|
||||||
|
float: right;
|
||||||
|
color: #02A1B1;
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 20px;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-content-modules {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 18px 5px 5px;
|
||||||
|
h4 {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 3px;
|
||||||
|
.card-panel {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 460px) {
|
||||||
|
.card {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 656px) {
|
||||||
|
.card {
|
||||||
|
width: 33.33333333%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
padding: 0 12px 5px 0;
|
||||||
|
}
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.card {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-create-space-modules {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
.card {
|
||||||
|
.card-panel {
|
||||||
|
background: #F5F5F5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,18 @@
|
|||||||
<?php $this->beginContent('@admin/views/layouts/main.php') ?>
|
<?php
|
||||||
<div class="panel panel-default">
|
/**
|
||||||
<div class="panel-heading">
|
* @link https://www.humhub.org/
|
||||||
<?= Yii::t('AdminModule.base', '<strong>Module </strong> administration'); ?>
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
<div class="help-block">
|
use humhub\modules\ui\view\helpers\ThemeHelper;
|
||||||
<?= Yii::t('AdminModule.modules', 'Modules extend the functionality of HumHub. Here you can install and manage modules from the HumHub Marketplace.') ?>
|
|
||||||
|
/* @var $content string */
|
||||||
|
?>
|
||||||
|
<div class="<?php if (ThemeHelper::isFluid()): ?>container-fluid<?php else: ?>container<?php endif; ?> container-cards container-modules">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<?= $content; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<?= \humhub\modules\admin\widgets\ModuleMenu::widget(); ?>
|
|
||||||
|
|
||||||
<?= $content; ?>
|
|
||||||
</div>
|
</div>
|
||||||
<?php $this->endContent(); ?>
|
|
||||||
|
@ -1,78 +1,30 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
use yii\helpers\Html;
|
use humhub\assets\CardsAsset;
|
||||||
use yii\helpers\Url;
|
use humhub\libs\Html;
|
||||||
|
use humhub\modules\admin\assets\ModuleAsset;
|
||||||
|
use humhub\modules\admin\widgets\ModuleFilters;
|
||||||
|
use humhub\modules\admin\widgets\Modules;
|
||||||
|
use humhub\modules\ui\icon\widgets\Icon;
|
||||||
|
use humhub\modules\ui\view\components\View;
|
||||||
|
|
||||||
/* @var $this \humhub\modules\ui\view\components\View */
|
/* @var $this View */
|
||||||
/* @var $installedModules array */
|
|
||||||
/* @var $deprecatedModuleIds array */
|
ModuleAsset::register($this);
|
||||||
/* @var $marketplaceUrls array */
|
CardsAsset::register($this);
|
||||||
?>
|
?>
|
||||||
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-heading">
|
||||||
<?php if (count($installedModules) == 0): ?>
|
<?= Yii::t('AdminModule.base', '<strong>Module </strong> Administration'); ?>
|
||||||
<br>
|
</div>
|
||||||
<div><?= Yii::t('AdminModule.modules', 'No modules installed yet. Install some to enhance the functionality!'); ?></div>
|
<div class="panel-body">
|
||||||
<?php endif; ?>
|
<?= ModuleFilters::widget(); ?>
|
||||||
|
</div>
|
||||||
<?php foreach ($installedModules
|
|
||||||
|
|
||||||
as $moduleId => $module) : ?>
|
|
||||||
<div class="media">
|
|
||||||
<img class="media-object img-rounded pull-left" data-src="holder.js/64x64" alt="64x64"
|
|
||||||
style="width: 64px; height: 64px;" src="<?= $module->getImage(); ?>">
|
|
||||||
|
|
||||||
<div class="media-body">
|
|
||||||
<h4 class="media-heading"><?= $module->getName(); ?>
|
|
||||||
<small>
|
|
||||||
<?php if (Yii::$app->hasModule($module->id)) : ?>
|
|
||||||
<span class="label label-info"><?= Yii::t('AdminModule.modules', 'Activated'); ?></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (in_array($module->id, $deprecatedModuleIds)): ?>
|
|
||||||
<span class="label label-default" data-toggle="tooltip" data-placement="bottom"
|
|
||||||
title="<?= Yii::t('AdminModule.modules', 'Not maintained or maintenance is about to be discontinued.'); ?>"><?= Yii::t('AdminModule.modules', 'Legacy'); ?></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</small>
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<p><?= $module->getDescription(); ?></p>
|
|
||||||
|
|
||||||
<div class="module-controls">
|
|
||||||
|
|
||||||
<?= Yii::t('AdminModule.modules', 'Version:'); ?> <?= $module->getVersion(); ?>
|
|
||||||
|
|
||||||
<?php if (Yii::$app->hasModule($module->id)) : ?>
|
|
||||||
<?php if ($module->getConfigUrl() != "") : ?>
|
|
||||||
· <?= Html::a(Yii::t('AdminModule.modules', 'Configure'), $module->getConfigUrl(), ['style' => 'font-weight:bold']); ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if ($module instanceof \humhub\modules\content\components\ContentContainerModule): ?>
|
|
||||||
· <?= Html::a(Yii::t('AdminModule.modules', 'Set as default'), Url::to(['/admin/module/set-as-default', 'moduleId' => $moduleId]), ['data-target' => '#globalModal']); ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
· <?= Html::a(Yii::t('AdminModule.modules', 'Disable'), Url::to(['/admin/module/disable', 'moduleId' => $moduleId]), ['data-method' => 'POST', 'data-confirm' => Yii::t('AdminModule.modules', 'Are you sure? *ALL* module data will be lost!')]); ?>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
· <?= Html::a(Yii::t('AdminModule.modules', 'Enable'), Url::to(['/admin/module/enable', 'moduleId' => $moduleId]), ['data-method' => 'POST', 'style' => 'font-weight:bold', 'data-loader' => "modal", 'data-message' => Yii::t('AdminModule.modules', 'Enable module...')]); ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (Yii::$app->moduleManager->canRemoveModule($moduleId)): ?>
|
|
||||||
· <?= Html::a(Yii::t('AdminModule.modules', 'Uninstall'), Url::to(['/admin/module/remove', 'moduleId' => $moduleId]), ['data-method' => 'POST', 'data-confirm' => Yii::t('AdminModule.modules', 'Are you sure? *ALL* module related data and files will be lost!')]); ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (isset($marketplaceUrls[$moduleId])): ?>
|
|
||||||
· <?= Html::a(Yii::t('AdminModule.modules', 'More info') . ' <i class="fa fa-external-link" aria-hidden="true"></i>'
|
|
||||||
, $marketplaceUrls[$moduleId],
|
|
||||||
['rel' => 'noopener', 'target' => '_blank']
|
|
||||||
); ?>
|
|
||||||
<?php else: ?>
|
|
||||||
· <?= Html::a(Yii::t('AdminModule.modules', 'More info'), Url::to(['/admin/module/info', 'moduleId' => $moduleId]), ['data-target' => '#globalModal']); ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr/>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?= Modules::widget() ?>
|
||||||
|
@ -178,8 +178,7 @@ class AdminMenu extends LeftNavigation
|
|||||||
{
|
{
|
||||||
/** @var Module $module */
|
/** @var Module $module */
|
||||||
$module = Yii::$app->getModule('marketplace');
|
$module = Yii::$app->getModule('marketplace');
|
||||||
|
if ($module === null || !$module->enabled) {
|
||||||
if (!$module->enabled) {
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\admin\widgets;
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\components\Widget;
|
||||||
|
use humhub\widgets\Button;
|
||||||
|
use Yii;
|
||||||
|
use yii\helpers\Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleActionsButton shows actions for module
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class ModuleActionButtons extends Widget
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Module
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Template for buttons
|
||||||
|
*/
|
||||||
|
public $template = '<div class="card-footer text-right">{buttons}</div>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
if ($this->module->isActivated) {
|
||||||
|
if ($this->module->getConfigUrl() != '') {
|
||||||
|
$html .= Button::asLink(Yii::t('AdminModule.modules', 'Configure'), $this->module->getConfigUrl())
|
||||||
|
->cssClass('btn btn-sm btn-info');
|
||||||
|
}
|
||||||
|
$html .= Button::asLink('<span class="glyphicon glyphicon-ok"></span> ' . Yii::t('AdminModule.modules', 'Activated'), Url::to(['/admin/module/disable', 'moduleId' => $this->module->id]))
|
||||||
|
->cssClass('btn btn-sm btn-info active')
|
||||||
|
->options([
|
||||||
|
'data-method' => 'POST',
|
||||||
|
'data-confirm' => Yii::t('AdminModule.modules', 'Are you sure? *ALL* module data will be lost!')
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$html .= Button::asLink(Yii::t('AdminModule.modules', 'Activate'), Url::to(['/admin/module/enable', 'moduleId' => $this->module->id]))
|
||||||
|
->cssClass('btn btn-sm btn-info')
|
||||||
|
->options([
|
||||||
|
'data-method' => 'POST',
|
||||||
|
'data-loader' => 'modal',
|
||||||
|
'data-message' => Yii::t('AdminModule.modules', 'Enable module...')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trim($html) === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_replace('{buttons}', $html, $this->template);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
66
protected/humhub/modules/admin/widgets/ModuleCard.php
Normal file
66
protected/humhub/modules/admin/widgets/ModuleCard.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\admin\widgets;
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\components\OnlineModule;
|
||||||
|
use humhub\components\Widget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleCard shows a card with module data
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class ModuleCard extends Widget
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Module|array
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string HTML wrapper around card
|
||||||
|
*/
|
||||||
|
public $template;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $view;
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
parent::init();
|
||||||
|
|
||||||
|
if (empty($this->template)) {
|
||||||
|
$this->template = '<div class="card card-module col-lg-3 col-md-4 col-sm-6 col-xs-12">{card}</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->view)) {
|
||||||
|
$this->view = 'moduleCard';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$onlineModule = new OnlineModule(['module' => $this->module]);
|
||||||
|
|
||||||
|
$card = $this->render($this->view, [
|
||||||
|
'module' => $this->module,
|
||||||
|
'isFeaturedModule' => $onlineModule->isFeatured,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return str_replace('{card}', $card, $this->template);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
164
protected/humhub/modules/admin/widgets/ModuleControls.php
Normal file
164
protected/humhub/modules/admin/widgets/ModuleControls.php
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\admin\widgets;
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\modules\content\components\ContentContainerModule;
|
||||||
|
use humhub\modules\ui\menu\MenuLink;
|
||||||
|
use humhub\modules\ui\menu\widgets\Menu;
|
||||||
|
use Yii;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Widget for rendering the context menu for module.
|
||||||
|
*/
|
||||||
|
class ModuleControls extends Menu
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Module
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public $template = '@admin/widgets/views/moduleControls';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->initControls();
|
||||||
|
return parent::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initControls()
|
||||||
|
{
|
||||||
|
$this->initInstalledModuleControls();
|
||||||
|
|
||||||
|
if ($marketplaceUrl = $this->getMarketplaceUrl($this->module)) {
|
||||||
|
$this->addEntry(new MenuLink([
|
||||||
|
'id' => 'marketplace-info',
|
||||||
|
'label' => Yii::t('AdminModule.base', 'Information'),
|
||||||
|
'url' => $marketplaceUrl,
|
||||||
|
'htmlOptions' => ['rel' => 'noopener', 'target' => '_blank'],
|
||||||
|
'icon' => 'external-link',
|
||||||
|
'sortOrder' => 500,
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
$this->addEntry(new MenuLink([
|
||||||
|
'id' => 'info',
|
||||||
|
'label' => Yii::t('AdminModule.base', 'Information'),
|
||||||
|
'url' => ['/admin/module/info', 'moduleId' => $this->module->id],
|
||||||
|
'htmlOptions' => ['data-target' => '#globalModal'],
|
||||||
|
'icon' => 'info-circle',
|
||||||
|
'sortOrder' => 600,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function initInstalledModuleControls()
|
||||||
|
{
|
||||||
|
if (!($this->module instanceof Module)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->module->isActivated) {
|
||||||
|
if ($this->module->getConfigUrl() != '') {
|
||||||
|
$this->addEntry(new MenuLink([
|
||||||
|
'id' => 'configure',
|
||||||
|
'label' => Yii::t('AdminModule.base', 'Configure'),
|
||||||
|
'url' => $this->module->getConfigUrl(),
|
||||||
|
'icon' => 'wrench',
|
||||||
|
'sortOrder' => 100,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->module instanceof ContentContainerModule) {
|
||||||
|
$this->addEntry(new MenuLink([
|
||||||
|
'id' => 'default',
|
||||||
|
'label' => Yii::t('AdminModule.base', 'Set as default'),
|
||||||
|
'url' => ['/admin/module/set-as-default', 'moduleId' => $this->module->id],
|
||||||
|
'htmlOptions' => ['data-target' => '#globalModal'],
|
||||||
|
'icon' => 'check-square',
|
||||||
|
'sortOrder' => 200,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addEntry(new MenuLink([
|
||||||
|
'id' => 'deactivate',
|
||||||
|
'label' => Yii::t('AdminModule.base', 'Deactivate'),
|
||||||
|
'url' => ['/admin/module/disable', 'moduleId' => $this->module->id],
|
||||||
|
'htmlOptions' => [
|
||||||
|
'data-method' => 'POST',
|
||||||
|
'data-confirm' => Yii::t('AdminModule.modules', 'Are you sure? *ALL* module data will be lost!'),
|
||||||
|
],
|
||||||
|
'icon' => 'minus-circle',
|
||||||
|
'sortOrder' => 300,
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
$this->addEntry(new MenuLink([
|
||||||
|
'id' => 'deactivate',
|
||||||
|
'label' => Yii::t('AdminModule.base', 'Activate'),
|
||||||
|
'url' => ['/admin/module/enable', 'moduleId' => $this->module->id],
|
||||||
|
'htmlOptions' => [
|
||||||
|
'data-method' => 'POST',
|
||||||
|
'data-loader' => 'modal',
|
||||||
|
'data-message' => Yii::t('AdminModule.modules', 'Enable module...'),
|
||||||
|
],
|
||||||
|
'icon' => 'check-circle',
|
||||||
|
'sortOrder' => 300,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Yii::$app->moduleManager->canRemoveModule($this->module->id)) {
|
||||||
|
$this->addEntry(new MenuLink([
|
||||||
|
'id' => 'uninstall',
|
||||||
|
'label' => Yii::t('AdminModule.base', 'Uninstall'),
|
||||||
|
'url' => ['/admin/module/remove', 'moduleId' => $this->module->id],
|
||||||
|
'htmlOptions' => [
|
||||||
|
'data-method' => 'POST',
|
||||||
|
'data-confirm' => Yii::t('AdminModule.modules', 'Are you sure? *ALL* module related data and files will be lost!'),
|
||||||
|
],
|
||||||
|
'icon' => 'trash',
|
||||||
|
'sortOrder' => 400,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getMarketplaceUrl($module): ?string
|
||||||
|
{
|
||||||
|
if (!Yii::$app->hasModule('marketplace')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static $onlineModules;
|
||||||
|
|
||||||
|
if (!isset($modules)) {
|
||||||
|
/* @var \humhub\modules\marketplace\Module $marketplaceModule */
|
||||||
|
$marketplaceModule = Yii::$app->getModule('marketplace');
|
||||||
|
$onlineModules = $marketplaceModule->onlineModuleManager->getModules();
|
||||||
|
}
|
||||||
|
|
||||||
|
return empty($onlineModules[$module->id]['marketplaceUrl'])
|
||||||
|
? null
|
||||||
|
: $onlineModules[$module->id]['marketplaceUrl'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getAttributes()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'class' => 'nav nav-pills preferences'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
protected/humhub/modules/admin/widgets/ModuleFilters.php
Normal file
45
protected/humhub/modules/admin/widgets/ModuleFilters.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\admin\widgets;
|
||||||
|
|
||||||
|
use humhub\libs\Html;
|
||||||
|
use humhub\modules\ui\icon\widgets\Icon;
|
||||||
|
use humhub\modules\ui\widgets\DirectoryFilters;
|
||||||
|
use Yii;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleFilters displays the filters on the modules list
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class ModuleFilters extends DirectoryFilters
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public $pageUrl = '/admin/module/list';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public $paginationUsed = false;
|
||||||
|
|
||||||
|
protected function initDefaultFilters()
|
||||||
|
{
|
||||||
|
$this->addFilter('keyword', [
|
||||||
|
'title' => Yii::t('AdminModule.base', 'Search'),
|
||||||
|
'placeholder' => Yii::t('AdminModule.base', 'Search...'),
|
||||||
|
'type' => 'input',
|
||||||
|
'wrapperClass' => 'col-md-7 form-search-filter-keyword',
|
||||||
|
'afterInput' => Html::submitButton(Icon::get('search'), ['class' => 'form-button-search']),
|
||||||
|
'sortOrder' => 100,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
105
protected/humhub/modules/admin/widgets/ModuleStatus.php
Normal file
105
protected/humhub/modules/admin/widgets/ModuleStatus.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\admin\widgets;
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\components\OnlineModule;
|
||||||
|
use humhub\components\Widget;
|
||||||
|
use Yii;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleStatus shows a status of the module
|
||||||
|
*
|
||||||
|
* @property-read string|null $status
|
||||||
|
* @property-read string|null $statusTitle
|
||||||
|
* @property-read string $class
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class ModuleStatus extends Widget
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Module
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string HTML wrapper around the status
|
||||||
|
*/
|
||||||
|
public $template = '<div class="card-status {class}">{status}</div>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null Cached status of the module
|
||||||
|
*/
|
||||||
|
private $_status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
return str_replace(['{status}', '{class}'], [$this->statusTitle, $this->class], $this->template);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return false|string|null
|
||||||
|
*/
|
||||||
|
public function getStatus()
|
||||||
|
{
|
||||||
|
if ($this->_status !== null) {
|
||||||
|
return $this->_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
$onlineModule = new OnlineModule(['module' => $this->module]);
|
||||||
|
|
||||||
|
if ($onlineModule->isProOnly) {
|
||||||
|
$this->_status = 'professional';
|
||||||
|
} else if ($onlineModule->isFeatured) {
|
||||||
|
$this->_status = 'featured';
|
||||||
|
} else if (!$onlineModule->isThirdParty) {
|
||||||
|
$this->_status = 'official';
|
||||||
|
} else if ($onlineModule->isPartner) {
|
||||||
|
$this->_status = 'partner';
|
||||||
|
} else if ($onlineModule->isDeprecated) {
|
||||||
|
$this->_status = 'deprecated';
|
||||||
|
} else {
|
||||||
|
$this->_status = 'none';
|
||||||
|
}
|
||||||
|
// TODO: Implement new status detection
|
||||||
|
|
||||||
|
return $this->_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusTitle(): string
|
||||||
|
{
|
||||||
|
switch ($this->status) {
|
||||||
|
case 'professional':
|
||||||
|
return Yii::t('AdminModule.modules', 'Professional Edition');
|
||||||
|
case 'featured':
|
||||||
|
return Yii::t('AdminModule.modules', 'Featured');
|
||||||
|
case 'official':
|
||||||
|
return Yii::t('AdminModule.modules', 'Official');
|
||||||
|
case 'partner':
|
||||||
|
return Yii::t('AdminModule.modules', 'Partner');
|
||||||
|
case 'deprecated':
|
||||||
|
return Yii::t('AdminModule.modules', 'Deprecated');
|
||||||
|
case 'new':
|
||||||
|
return Yii::t('AdminModule.modules', 'New');
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClass(): string
|
||||||
|
{
|
||||||
|
return 'card-status-' . $this->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
107
protected/humhub/modules/admin/widgets/Modules.php
Normal file
107
protected/humhub/modules/admin/widgets/Modules.php
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\admin\widgets;
|
||||||
|
|
||||||
|
use humhub\components\Widget;
|
||||||
|
use humhub\modules\marketplace\Module;
|
||||||
|
use Yii;
|
||||||
|
use yii\helpers\ArrayHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modules displays the modules list
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class Modules extends Widget
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $groups;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->initDefaultGroups();
|
||||||
|
|
||||||
|
parent::init();
|
||||||
|
|
||||||
|
ArrayHelper::multisort($this->groups, 'sortOrder');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function initDefaultGroups()
|
||||||
|
{
|
||||||
|
/* @var Module $marketplaceModule */
|
||||||
|
$marketplaceModule = Yii::$app->getModule('marketplace');
|
||||||
|
if ($marketplaceModule->isFilteredBySingleTag('not_installed')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$installedModules = Yii::$app->moduleManager->getModules();
|
||||||
|
|
||||||
|
ArrayHelper::multisort($installedModules, 'isActivated', SORT_DESC);
|
||||||
|
|
||||||
|
$this->addGroup('installed', [
|
||||||
|
'title' => Yii::t('AdminModule.modules', 'Installed'),
|
||||||
|
'modules' => Yii::$app->moduleManager->filterModules($installedModules),
|
||||||
|
'count' => count($installedModules),
|
||||||
|
'noModulesMessage' => Yii::t('AdminModule.base', 'No modules installed yet. Install some to enhance the functionality!'),
|
||||||
|
'sortOrder' => 100,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addGroup(string $groupType, array $group)
|
||||||
|
{
|
||||||
|
$this->groups[$groupType] = $group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$modules = '';
|
||||||
|
|
||||||
|
$alwaysVisibleGroup = 'availableUpdates';
|
||||||
|
$displaySingleGroup = true;
|
||||||
|
foreach ($this->groups as $groupType => $group) {
|
||||||
|
if ($groupType !== $alwaysVisibleGroup && !empty($group['modules'])) {
|
||||||
|
$displaySingleGroup = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$singleGroupPrinted = false;
|
||||||
|
foreach ($this->groups as $groupType => $group) {
|
||||||
|
if ($singleGroupPrinted) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (empty($group['count'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($displaySingleGroup && $groupType !== $alwaysVisibleGroup) {
|
||||||
|
$singleGroupPrinted = true;
|
||||||
|
$group['title'] = false;
|
||||||
|
}
|
||||||
|
$group['type'] = $groupType;
|
||||||
|
$renderedGroup = $this->render('moduleGroup', $group);
|
||||||
|
|
||||||
|
if (isset($group['groupTemplate'])) {
|
||||||
|
$renderedGroup = str_replace('{group}', $renderedGroup, $group['groupTemplate']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$modules .= $renderedGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
protected/humhub/modules/admin/widgets/views/moduleCard.php
Normal file
35
protected/humhub/modules/admin/widgets/views/moduleCard.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\libs\Html;
|
||||||
|
use humhub\modules\admin\widgets\ModuleActionButtons;
|
||||||
|
use humhub\modules\admin\widgets\ModuleControls;
|
||||||
|
use humhub\modules\admin\widgets\ModuleStatus;
|
||||||
|
use humhub\modules\ui\icon\widgets\Icon;
|
||||||
|
|
||||||
|
/* @var $module Module */
|
||||||
|
/* @var $isFeaturedModule bool */
|
||||||
|
?>
|
||||||
|
<div class="card-panel">
|
||||||
|
<?= ModuleStatus::widget(['module' => $module]) ?>
|
||||||
|
<div class="card-header">
|
||||||
|
<?= Html::img($module->getImage(), [
|
||||||
|
'class' => 'media-object img-rounded',
|
||||||
|
'data-src' => 'holder.js/94x94',
|
||||||
|
'alt' => '94x94',
|
||||||
|
'style' => 'width:94px;height:94px',
|
||||||
|
]) ?>
|
||||||
|
<?= ModuleControls::widget(['module' => $module]) ?>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title"><?= $module->getName() . ($isFeaturedModule ? ' ' . Icon::get('star')->color('info') : '') ?></div>
|
||||||
|
<div><?= $module->getVersion() ?></div>
|
||||||
|
<div><?= $module->getDescription() ?></div>
|
||||||
|
</div>
|
||||||
|
<?= ModuleActionButtons::widget(['module' => $module]) ?>
|
||||||
|
</div>
|
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
use humhub\libs\Html;
|
||||||
|
use humhub\modules\ui\icon\widgets\Icon;
|
||||||
|
use humhub\modules\ui\menu\MenuEntry;
|
||||||
|
|
||||||
|
/* @var MenuEntry[] $entries */
|
||||||
|
/* @var array $options */
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?= Html::beginTag('ul', $options)?>
|
||||||
|
<li class="dropdown ">
|
||||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#"
|
||||||
|
aria-label="<?= Yii::t('base', 'Toggle stream entry menu'); ?>" aria-haspopup="true">
|
||||||
|
<?= Icon::get('dropdownToggle') ?>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ul class="dropdown-menu pull-right">
|
||||||
|
<?php foreach ($entries as $entry) : ?>
|
||||||
|
<li>
|
||||||
|
<?= $entry->render() ?>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<?= Html::endTag('ul')?>
|
42
protected/humhub/modules/admin/widgets/views/moduleGroup.php
Normal file
42
protected/humhub/modules/admin/widgets/views/moduleGroup.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\modules\admin\widgets\ModuleCard;
|
||||||
|
|
||||||
|
/* @var string $type */
|
||||||
|
/* @var string|bool $title */
|
||||||
|
/* @var int $count */
|
||||||
|
/* @var string $noModulesMessage */
|
||||||
|
/* @var string $view */
|
||||||
|
/* @var string $moduleTemplate */
|
||||||
|
/* @var Module[] $modules */
|
||||||
|
?>
|
||||||
|
<?php if ($title !== false) : ?>
|
||||||
|
<h4 class="modules-type"><?= $title ?> (<span class="group-modules-count-<?= $type ?>"><?= $count ?></span>)</h4>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="row cards">
|
||||||
|
<?php if (empty($modules)) : ?>
|
||||||
|
<div class="col-md-12 cards-no-results">
|
||||||
|
<?php if ($count) : ?>
|
||||||
|
<strong><?= Yii::t('AdminModule.modules', 'No modules found.') ?></strong><br/>
|
||||||
|
<?= Yii::t('AdminModule.modules', 'Try other keywords or remove filters.') ?>
|
||||||
|
<?php elseif (isset($noModulesMessage)) : ?>
|
||||||
|
<strong><?= $noModulesMessage ?></strong>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php foreach ($modules as $module) : ?>
|
||||||
|
<?= ModuleCard::widget([
|
||||||
|
'module' => $module,
|
||||||
|
'view' => $view ?? null,
|
||||||
|
'template' => $moduleTemplate ?? null,
|
||||||
|
]); ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
@ -156,7 +156,7 @@ class ContentContainerModuleManager extends \yii\base\Component
|
|||||||
$this->_available = [];
|
$this->_available = [];
|
||||||
|
|
||||||
foreach (Yii::$app->moduleManager->getModules() as $id => $module) {
|
foreach (Yii::$app->moduleManager->getModules() as $id => $module) {
|
||||||
if ($module instanceof ContentContainerModule && Yii::$app->hasModule($module->id) &&
|
if ($module instanceof ContentContainerModule && $module->isActivated &&
|
||||||
$module->hasContentContainerType($this->contentContainer->className())) {
|
$module->hasContentContainerType($this->contentContainer->className())) {
|
||||||
$this->_available[$module->id] = $module;
|
$this->_available[$module->id] = $module;
|
||||||
}
|
}
|
||||||
|
108
protected/humhub/modules/content/widgets/ModuleActionButtons.php
Normal file
108
protected/humhub/modules/content/widgets/ModuleActionButtons.php
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\content\widgets;
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\components\Widget;
|
||||||
|
use humhub\modules\content\components\behaviors\CompatModuleManager;
|
||||||
|
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||||
|
use humhub\modules\space\models\Space;
|
||||||
|
use humhub\widgets\Button;
|
||||||
|
use Yii;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleActionsButton shows actions for module of Content Container
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class ModuleActionButtons extends Widget
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Module
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ContentContainerActiveRecord|CompatModuleManager
|
||||||
|
*/
|
||||||
|
public $contentContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Template for buttons
|
||||||
|
*/
|
||||||
|
public $template = '<div class="card-footer text-right">{buttons}</div>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
if ($this->module->getContentContainerConfigUrl($this->contentContainer) && $this->contentContainer->isModuleEnabled($this->module->id)) {
|
||||||
|
$html .= Button::asLink(Yii::t('ContentModule.modules', 'Configure'), $this->module->getContentContainerConfigUrl($this->contentContainer))
|
||||||
|
->cssClass('btn btn-sm btn-info configure-module-' . $this->module->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->contentContainer->canDisableModule($this->module->id)) {
|
||||||
|
$html .= Button::asLink('<span class="glyphicon glyphicon-ok"></span> ' . Yii::t('ContentModule.modules', 'Activated'), '#')
|
||||||
|
->cssClass('btn btn-sm btn-info active disable disable-module-' . $this->module->id)
|
||||||
|
->style($this->contentContainer->isModuleEnabled($this->module->id) ? '' : 'display:none')
|
||||||
|
->options([
|
||||||
|
'data-action-click' => 'content.container.disableModule',
|
||||||
|
'data-action-url' => $this->getDisableUrl(),
|
||||||
|
'data-reload' => '1',
|
||||||
|
'data-action-confirm' => $this->getDisableConfirmationText(),
|
||||||
|
'data-ui-loader' => 1,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= Button::asLink(Yii::t('ContentModule.modules', 'Enable'), '#')
|
||||||
|
->cssClass('btn btn-sm btn-info enable enable-module-' . $this->module->id)
|
||||||
|
->style($this->contentContainer->isModuleEnabled($this->module->id) ? 'display:none' : '')
|
||||||
|
->options([
|
||||||
|
'data-action-click' => 'content.container.enableModule',
|
||||||
|
'data-action-url' => $this->getEnableUrl(),
|
||||||
|
'data-reload' => '1',
|
||||||
|
'data-ui-loader' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (trim($html) === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_replace('{buttons}', $html, $this->template);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isSpace(): bool
|
||||||
|
{
|
||||||
|
return $this->contentContainer instanceof Space;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDisableUrl(): string
|
||||||
|
{
|
||||||
|
$route = $this->isSpace() ? '/space/manage/module/disable' : '/user/account/disable-module';
|
||||||
|
return $this->contentContainer->createUrl($route, ['moduleId' => $this->module->id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDisableConfirmationText(): string
|
||||||
|
{
|
||||||
|
return $this->isSpace()
|
||||||
|
? Yii::t('ContentModule.manage', 'Are you sure? *ALL* module data for this space will be deleted!')
|
||||||
|
: Yii::t('ContentModule.manage', 'Are you really sure? *ALL* module data for your profile will be deleted!');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getEnableUrl(): string
|
||||||
|
{
|
||||||
|
$route = $this->isSpace() ? '/space/manage/module/enable' : '/user/account/enable-module';
|
||||||
|
return $this->contentContainer->createUrl($route, ['moduleId' => $this->module->id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
40
protected/humhub/modules/content/widgets/ModuleCard.php
Normal file
40
protected/humhub/modules/content/widgets/ModuleCard.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\content\widgets;
|
||||||
|
|
||||||
|
use humhub\modules\admin\widgets\ModuleCard as AdminModuleCard;
|
||||||
|
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleCard shows a card with module data of Content Container
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class ModuleCard extends AdminModuleCard
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ContentContainerActiveRecord
|
||||||
|
*/
|
||||||
|
public $contentContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$card = $this->render($this->view, [
|
||||||
|
'module' => $this->module,
|
||||||
|
'contentContainer' => $this->contentContainer,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return str_replace('{card}', $card, $this->template);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\libs\Html;
|
||||||
|
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||||
|
use humhub\modules\content\widgets\ModuleActionButtons;
|
||||||
|
|
||||||
|
/* @var Module $module */
|
||||||
|
/* @var ContentContainerActiveRecord $contentContainer */
|
||||||
|
?>
|
||||||
|
<div class="card-panel">
|
||||||
|
<div class="card-header">
|
||||||
|
<?= Html::img($module->getImage(), [
|
||||||
|
'class' => 'media-object img-rounded',
|
||||||
|
'data-src' => 'holder.js/94x94',
|
||||||
|
'alt' => '94x94',
|
||||||
|
'style' => 'width:94px;height:94px',
|
||||||
|
]) ?>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title"><?= $module->getName() ?></div>
|
||||||
|
</div>
|
||||||
|
<?= ModuleActionButtons::widget([
|
||||||
|
'module' => $module,
|
||||||
|
'contentContainer' => $contentContainer,
|
||||||
|
]) ?>
|
||||||
|
</div>
|
@ -39,12 +39,12 @@ class FileHandlerCollection extends \yii\base\Component
|
|||||||
public $type;
|
public $type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \humhub\modules\file\models\File
|
* @var \humhub\modules\file\models\File
|
||||||
*/
|
*/
|
||||||
public $file = null;
|
public $file = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var type
|
* @var BaseFileHandler[]
|
||||||
*/
|
*/
|
||||||
public $handlers = [];
|
public $handlers = [];
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ class FileHandlerCollection extends \yii\base\Component
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns registered handlers by type
|
* Returns registered handlers by type
|
||||||
*
|
*
|
||||||
* @param string|array $type or multiple type array
|
* @param string|array $type or multiple type array
|
||||||
* @param \humhub\modules\file\models\File $file the file (optional)
|
* @param \humhub\modules\file\models\File $file the file (optional)
|
||||||
* @return BaseFileHandler[] the registered handlers
|
* @return BaseFileHandler[] the registered handlers
|
||||||
|
@ -8,10 +8,21 @@
|
|||||||
|
|
||||||
namespace humhub\modules\marketplace;
|
namespace humhub\modules\marketplace;
|
||||||
|
|
||||||
|
use humhub\components\Module as CoreModule;
|
||||||
|
use humhub\components\OnlineModule;
|
||||||
|
use humhub\modules\admin\events\ModulesEvent;
|
||||||
|
use humhub\modules\admin\libs\HumHubAPI;
|
||||||
|
use humhub\modules\admin\widgets\ModuleControls;
|
||||||
|
use humhub\modules\admin\widgets\ModuleFilters;
|
||||||
|
use humhub\modules\admin\widgets\Modules;
|
||||||
|
use humhub\modules\marketplace\models\Module as ModelModule;
|
||||||
|
use humhub\modules\share_between_humhub\helpers\Url;
|
||||||
|
use humhub\modules\ui\icon\widgets\Icon;
|
||||||
|
use humhub\modules\ui\menu\MenuLink;
|
||||||
|
use humhub\widgets\Button;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\base\BaseObject;
|
use yii\base\BaseObject;
|
||||||
use yii\base\Event;
|
use yii\base\Event;
|
||||||
use yii\helpers\Url;
|
|
||||||
|
|
||||||
class Events extends BaseObject
|
class Events extends BaseObject
|
||||||
{
|
{
|
||||||
@ -23,10 +34,7 @@ class Events extends BaseObject
|
|||||||
*/
|
*/
|
||||||
public static function onConsoleApplicationInit($event)
|
public static function onConsoleApplicationInit($event)
|
||||||
{
|
{
|
||||||
/** @var Module $module */
|
if (!self::getEnabledMarketplaceModule()) {
|
||||||
$module = Yii::$app->getModule('marketplace');
|
|
||||||
|
|
||||||
if (!$module->enabled) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,50 +42,291 @@ class Events extends BaseObject
|
|||||||
$application->controllerMap['module'] = commands\MarketplaceController::class;
|
$application->controllerMap['module'] = commands\MarketplaceController::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function onAdminModuleMenuInit($events)
|
|
||||||
{
|
|
||||||
/** @var Module $module */
|
|
||||||
$module = Yii::$app->getModule('marketplace');
|
|
||||||
|
|
||||||
if (!$module->enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$updatesBadge = '';
|
|
||||||
$updatesCount = count($module->onlineModuleManager->getModuleUpdates());
|
|
||||||
if ($updatesCount > 0) {
|
|
||||||
$updatesBadge = ' <span class="label label-danger">' . $updatesCount . '</span>';
|
|
||||||
} else {
|
|
||||||
$updatesBadge = ' <span class="label label-default">0</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$events->sender->addItem([
|
|
||||||
'label' => Yii::t('MarketplaceModule.base', 'Browse online'),
|
|
||||||
'url' => Url::to(['/marketplace/browse']),
|
|
||||||
'sortOrder' => 200,
|
|
||||||
'isActive' => (Yii::$app->controller->id == 'browse'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$events->sender->addItem([
|
|
||||||
'label' => Yii::t('MarketplaceModule.base', 'Purchases'),
|
|
||||||
'url' => Url::to(['/marketplace/purchase']),
|
|
||||||
'sortOrder' => 300,
|
|
||||||
'isActive' => (Yii::$app->controller->id == 'purchase'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$events->sender->addItem([
|
|
||||||
'label' => Yii::t('MarketplaceModule.base', 'Available updates') . $updatesBadge,
|
|
||||||
'url' => Url::to(['/marketplace/update']),
|
|
||||||
'sortOrder' => 400,
|
|
||||||
'isActive' => (Yii::$app->controller->id == 'update'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function onHourlyCron($event)
|
public static function onHourlyCron($event)
|
||||||
{
|
{
|
||||||
Yii::$app->queue->push(new jobs\PeActiveCheckJob());
|
Yii::$app->queue->push(new jobs\PeActiveCheckJob());
|
||||||
Yii::$app->queue->push(new jobs\ModuleCleanupsJob());
|
Yii::$app->queue->push(new jobs\ModuleCleanupsJob());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function getEnabledMarketplaceModule(): ?Module
|
||||||
|
{
|
||||||
|
/* @var Module $marketplaceModule */
|
||||||
|
$marketplaceModule = Yii::$app->getModule('marketplace');
|
||||||
|
|
||||||
|
return $marketplaceModule->enabled ? $marketplaceModule : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function onAdminModuleFiltersInit($event)
|
||||||
|
{
|
||||||
|
if (!($marketplaceModule = self::getEnabledMarketplaceModule())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var ModuleFilters $moduleFilters */
|
||||||
|
$moduleFilters = $event->sender;
|
||||||
|
|
||||||
|
$marketplaceModule->onlineModuleManager->getModules();
|
||||||
|
$categories = $marketplaceModule->onlineModuleManager->getCategories();
|
||||||
|
if (!empty($categories)) {
|
||||||
|
$moduleFilters->addFilter('categoryId', [
|
||||||
|
'title' => Yii::t('MarketplaceModule.base', 'Categories'),
|
||||||
|
'type' => 'dropdown',
|
||||||
|
'options' => $categories,
|
||||||
|
'wrapperClass' => 'col-md-3',
|
||||||
|
'sortOrder' => 200,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$moduleFilters->addFilter('tags', [
|
||||||
|
'title' => Yii::t('MarketplaceModule.base', 'Tags'),
|
||||||
|
'type' => 'tags',
|
||||||
|
'tags' => [
|
||||||
|
'' => Yii::t('MarketplaceModule.base', 'All'),
|
||||||
|
'installed' => Yii::t('MarketplaceModule.base', 'Installed'),
|
||||||
|
'not_installed' => Yii::t('MarketplaceModule.base', 'Not Installed'),
|
||||||
|
'professional' => Yii::t('MarketplaceModule.base', 'Professional Edition'),
|
||||||
|
'featured' => Yii::t('MarketplaceModule.base', 'Featured'),
|
||||||
|
'official' => Yii::t('MarketplaceModule.base', 'Official'),
|
||||||
|
'partner' => Yii::t('MarketplaceModule.base', 'Partner'),
|
||||||
|
'new' => Yii::t('MarketplaceModule.base', 'New'),
|
||||||
|
],
|
||||||
|
'wrapperClass' => 'col-md-12 form-search-filter-tags',
|
||||||
|
'sortOrder' => 20000,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function onAdminModuleFiltersAfterRun($event)
|
||||||
|
{
|
||||||
|
if (!self::getEnabledMarketplaceModule()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$latestVersion = HumHubAPI::getLatestHumHubVersion();
|
||||||
|
if (!$latestVersion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version_compare($latestVersion, Yii::$app->version, '>')) {
|
||||||
|
$updateUrl = 'https://docs.humhub.org/docs/admin/updating/';
|
||||||
|
if (Yii::$app->hasModule('updater')) {
|
||||||
|
$updateUrl = Url::to(['/updater/update']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = [
|
||||||
|
'class' => 'directory-filters-footer-warning',
|
||||||
|
'icon' => 'info-circle',
|
||||||
|
'info' => Yii::t('MarketplaceModule.base', 'A new HumHub update is available. Install it now to keep your network up to date and to have access to the latest module versions.'),
|
||||||
|
'link' => Button::asLink(Yii::t('MarketplaceModule.base', 'Update HumHub now'), $updateUrl)
|
||||||
|
->cssClass('btn btn-primary'),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$info = [
|
||||||
|
'class' => 'directory-filters-footer-info',
|
||||||
|
'icon' => 'check-circle',
|
||||||
|
'info' => Yii::t('MarketplaceModule.base', 'This HumHub installation is up to date!'),
|
||||||
|
'link' => Button::asLink('https://www.humhub.com', 'https://www.humhub.com')
|
||||||
|
->cssClass('btn btn-info'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var ModuleFilters $moduleFilters */
|
||||||
|
$moduleFilters = $event->sender;
|
||||||
|
$event->result .= $moduleFilters->render('@humhub/modules/marketplace/widgets/views/moduleUpdateInfo', $info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function onAdminModulesInit($event)
|
||||||
|
{
|
||||||
|
if (!($marketplaceModule = self::getEnabledMarketplaceModule())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var Modules $modulesWidget */
|
||||||
|
$modulesWidget = $event->sender;
|
||||||
|
|
||||||
|
$updateModules = $marketplaceModule->onlineModuleManager->getAvailableUpdateModules();
|
||||||
|
if ($updateModulesCount = count($updateModules)) {
|
||||||
|
$updateAllButton = Button::info(Yii::t('MarketplaceModule.base', 'Update all'))
|
||||||
|
->options([
|
||||||
|
'data-stop-title' => Icon::get('pause') . ' ' . Yii::t('MarketplaceModule.base', 'Stop updating'),
|
||||||
|
'data-stop-class' => 'btn btn-warning pull-right',
|
||||||
|
])
|
||||||
|
->action('marketplace.updateAll')
|
||||||
|
->loader(false)
|
||||||
|
->cssClass('active pull-right');
|
||||||
|
|
||||||
|
$modulesWidget->addGroup('availableUpdates', [
|
||||||
|
'title' => Yii::t('MarketplaceModule.base', 'Available Updates'),
|
||||||
|
'modules' => $updateModules,
|
||||||
|
'count' => $updateModulesCount,
|
||||||
|
'view' => '@humhub/modules/marketplace/widgets/views/moduleUpdateCard',
|
||||||
|
'groupTemplate' => '<div class="container-module-updates">' . $updateAllButton . '{group}</div>',
|
||||||
|
'moduleTemplate' => '<div class="card card-module col-lg-2 col-md-3 col-sm-4 col-xs-6">{card}</div>',
|
||||||
|
'sortOrder' => 10,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$marketplaceModule->isFilteredBySingleTag('installed')) {
|
||||||
|
$onlineModules = $marketplaceModule->onlineModuleManager->getNotInstalledModules();
|
||||||
|
if ($onlineModulesCount = count($onlineModules)) {
|
||||||
|
$modulesWidget->addGroup('notInstalled', [
|
||||||
|
'title' => Yii::t('AdminModule.modules', 'Not Installed'),
|
||||||
|
'modules' => Yii::$app->moduleManager->filterModules($onlineModules),
|
||||||
|
'count' => $onlineModulesCount,
|
||||||
|
'view' => '@humhub/modules/marketplace/widgets/views/moduleInstallCard',
|
||||||
|
'sortOrder' => 200,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function onAdminModuleManagerAfterFilterModules(ModulesEvent $event)
|
||||||
|
{
|
||||||
|
if (!self::getEnabledMarketplaceModule()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($event->modules)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($event->modules as $m => $module) {
|
||||||
|
if (!self::isFilteredModule($module)) {
|
||||||
|
unset($event->modules[$m]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param CoreModule|ModelModule $module
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private static function isFilteredModule($module): bool
|
||||||
|
{
|
||||||
|
return self::isFilteredModuleByCategory($module) &&
|
||||||
|
self::isFilteredModuleByTags($module);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param CoreModule|ModelModule $module
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private static function isFilteredModuleByCategory($module): bool
|
||||||
|
{
|
||||||
|
$categoryId = Yii::$app->request->get('categoryId', null);
|
||||||
|
|
||||||
|
if (empty($categoryId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$moduleCategories = (new OnlineModule(['module' => $module]))->categories;
|
||||||
|
|
||||||
|
return empty($moduleCategories) ? false : in_array($categoryId, $moduleCategories);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param CoreModule|ModelModule $module
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private static function isFilteredModuleByTags($module): bool
|
||||||
|
{
|
||||||
|
$tags = Yii::$app->request->get('tags', null);
|
||||||
|
|
||||||
|
if (empty($tags)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags = explode(',', $tags);
|
||||||
|
|
||||||
|
$onlineModule = new OnlineModule(['module' => $module]);
|
||||||
|
|
||||||
|
$searchInstalled = in_array('installed', $tags);
|
||||||
|
$searchNotInstalled = in_array('not_installed', $tags);
|
||||||
|
if ($searchInstalled && $searchNotInstalled && count($tags) === 2) {
|
||||||
|
// No need to filter when only 2 tags "Installed" and "Not Installed" are selected
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ($searchInstalled && !$searchNotInstalled && !$onlineModule->isInstalled) {
|
||||||
|
// Exclude all NOT Installed modules when requested only Installed modules
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!$searchInstalled && $searchNotInstalled && $onlineModule->isInstalled) {
|
||||||
|
// Exclude all Installed modules when requested only NOT Installed modules
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (($searchInstalled || $searchNotInstalled) && count($tags) === 1) {
|
||||||
|
// No need to next filter when only 1 tag "Installed" or "Not Installed" is selected
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
switch ($tag) {
|
||||||
|
case 'professional':
|
||||||
|
if ($onlineModule->isProOnly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'featured':
|
||||||
|
if ($onlineModule->isFeatured) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'official':
|
||||||
|
if (!$onlineModule->isThirdParty) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'partner':
|
||||||
|
if ($onlineModule->isPartner) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'new':
|
||||||
|
// TODO: Filter by new status
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function onAdminModuleControlsInit($event)
|
||||||
|
{
|
||||||
|
if (!self::getEnabledMarketplaceModule()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var ModuleControls $moduleControls */
|
||||||
|
$moduleControls = $event->sender;
|
||||||
|
|
||||||
|
$module = $moduleControls->module;
|
||||||
|
|
||||||
|
if (!($module instanceof ModelModule)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \humhub\modules\marketplace\models\Module $module */
|
||||||
|
|
||||||
|
if ($module->isNonFree) {
|
||||||
|
$moduleControls->addEntry(new MenuLink([
|
||||||
|
'id' => 'marketplace-licence-key',
|
||||||
|
'label' => Yii::t('MarketplaceModule.base', 'Add Licence Key'),
|
||||||
|
'url' => ['/marketplace/purchase'],
|
||||||
|
'htmlOptions' => ['data-target' => '#globalModal'],
|
||||||
|
'icon' => 'key',
|
||||||
|
'sortOrder' => 1000,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($module->isThirdParty) {
|
||||||
|
$moduleControls->addEntry(new MenuLink([
|
||||||
|
'id' => 'marketplace-third-party',
|
||||||
|
'label' => Yii::t('MarketplaceModule.base', 'Third-party')
|
||||||
|
. ($module->isCommunity ? ' - ' . Yii::t('MarketplaceModule.base', 'Community') : ''),
|
||||||
|
'url' => ['/marketplace/browse/thirdparty-disclaimer'],
|
||||||
|
'htmlOptions' => ['data-target' => '#globalModal'],
|
||||||
|
'icon' => 'info-circle',
|
||||||
|
'sortOrder' => 1100,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
namespace humhub\modules\marketplace;
|
namespace humhub\modules\marketplace;
|
||||||
|
|
||||||
use humhub\components\Module as BaseModule;
|
use humhub\components\Module as BaseModule;
|
||||||
use humhub\models\Setting;
|
|
||||||
use humhub\modules\marketplace\components\HumHubApiClient;
|
use humhub\modules\marketplace\components\HumHubApiClient;
|
||||||
use humhub\modules\marketplace\components\LicenceManager;
|
use humhub\modules\marketplace\components\LicenceManager;
|
||||||
use humhub\modules\marketplace\models\Licence;
|
use humhub\modules\marketplace\models\Licence;
|
||||||
@ -20,6 +19,7 @@ use Yii;
|
|||||||
* The Marketplace modules contains all the capabilities to interact with the offical HumHub marketplace.
|
* The Marketplace modules contains all the capabilities to interact with the offical HumHub marketplace.
|
||||||
* The core functions are the ability to easily install or update modules from the remote module directory.
|
* The core functions are the ability to easily install or update modules from the remote module directory.
|
||||||
*
|
*
|
||||||
|
* @property-read Licence $licence
|
||||||
* @property OnlineModuleManager $onlineModuleManager
|
* @property OnlineModuleManager $onlineModuleManager
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
@ -127,4 +127,23 @@ class Module extends BaseModule
|
|||||||
|
|
||||||
return $this->_humhubApi;
|
return $this->_humhubApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the modules list is filtered by single tag
|
||||||
|
*
|
||||||
|
* @param string $tag
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isFilteredBySingleTag(string $tag): bool
|
||||||
|
{
|
||||||
|
$tags = Yii::$app->request->get('tags', null);
|
||||||
|
|
||||||
|
if (empty($tags)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags = explode(',', $tags);
|
||||||
|
|
||||||
|
return count($tags) === 1 && $tags[0] == $tag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
32
protected/humhub/modules/marketplace/assets/Assets.php
Normal file
32
protected/humhub/modules/marketplace/assets/Assets.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\marketplace\assets;
|
||||||
|
|
||||||
|
use humhub\components\assets\AssetBundle;
|
||||||
|
|
||||||
|
class Assets extends AssetBundle
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public $sourcePath = '@marketplace/resources';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public $css = [
|
||||||
|
'css/modules.css'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public $js = [
|
||||||
|
'js/humhub.marketplace.js'
|
||||||
|
];
|
||||||
|
}
|
@ -9,15 +9,14 @@
|
|||||||
namespace humhub\modules\marketplace\components;
|
namespace humhub\modules\marketplace\components;
|
||||||
|
|
||||||
use humhub\components\ModuleEvent;
|
use humhub\components\ModuleEvent;
|
||||||
use humhub\libs\HttpClient;
|
|
||||||
use humhub\modules\admin\libs\HumHubAPI;
|
use humhub\modules\admin\libs\HumHubAPI;
|
||||||
|
use humhub\modules\marketplace\models\Module as ModelModule;
|
||||||
use humhub\modules\marketplace\Module;
|
use humhub\modules\marketplace\Module;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\base\Component;
|
use yii\base\Component;
|
||||||
use yii\web\HttpException;
|
use yii\web\HttpException;
|
||||||
use yii\base\Exception;
|
use yii\base\Exception;
|
||||||
use yii\helpers\FileHelper;
|
use yii\helpers\FileHelper;
|
||||||
use humhub\libs\CURLHelper;
|
|
||||||
use ZipArchive;
|
use ZipArchive;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -286,4 +285,45 @@ class OnlineModuleManager extends Component
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get only not installed modules
|
||||||
|
*
|
||||||
|
* @return ModelModule[]
|
||||||
|
*/
|
||||||
|
public function getNotInstalledModules(): array
|
||||||
|
{
|
||||||
|
/** @var Module $module */
|
||||||
|
$marketplaceModule = Yii::$app->getModule('marketplace');
|
||||||
|
|
||||||
|
$modules = $this->getModules();
|
||||||
|
|
||||||
|
foreach ($modules as $o => $module) {
|
||||||
|
$onlineModule = new ModelModule($module);
|
||||||
|
if ($onlineModule->isInstalled() ||
|
||||||
|
($onlineModule->isDeprecated && $marketplaceModule->hideLegacyModules)) {
|
||||||
|
unset($modules[$o]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$modules[$o] = $onlineModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get modules with available update
|
||||||
|
*
|
||||||
|
* @return ModelModule[]
|
||||||
|
*/
|
||||||
|
public function getAvailableUpdateModules(): array
|
||||||
|
{
|
||||||
|
$modules = $this->getModuleUpdates(false);
|
||||||
|
|
||||||
|
foreach ($modules as $o => $module) {
|
||||||
|
$modules[$o] = new ModelModule($module);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use humhub\commands\CronController;
|
use humhub\commands\CronController;
|
||||||
|
use humhub\components\ModuleManager;
|
||||||
|
use humhub\modules\admin\widgets\ModuleControls;
|
||||||
|
use humhub\modules\admin\widgets\ModuleFilters;
|
||||||
|
use humhub\modules\admin\widgets\Modules;
|
||||||
use humhub\modules\marketplace\Events;
|
use humhub\modules\marketplace\Events;
|
||||||
use humhub\modules\admin\widgets\ModuleMenu;
|
|
||||||
use humhub\modules\marketplace\Module;
|
use humhub\modules\marketplace\Module;
|
||||||
|
|
||||||
/** @noinspection MissedFieldInspection */
|
/** @noinspection MissedFieldInspection */
|
||||||
@ -21,7 +24,11 @@ return [
|
|||||||
'professional-edition' => 'humhub\modules\marketplace\commands\ProfessionalEditionController'
|
'professional-edition' => 'humhub\modules\marketplace\commands\ProfessionalEditionController'
|
||||||
],
|
],
|
||||||
'events' => [
|
'events' => [
|
||||||
[ModuleMenu::class, ModuleMenu::EVENT_INIT, [Events::class, 'onAdminModuleMenuInit']],
|
|
||||||
[CronController::class, CronController::EVENT_ON_HOURLY_RUN, [Events::class, 'onHourlyCron']],
|
[CronController::class, CronController::EVENT_ON_HOURLY_RUN, [Events::class, 'onHourlyCron']],
|
||||||
|
[ModuleFilters::class, ModuleFilters::EVENT_INIT, [Events::class, 'onAdminModuleFiltersInit']],
|
||||||
|
[ModuleFilters::class, ModuleFilters::EVENT_AFTER_RUN, [Events::class, 'onAdminModuleFiltersAfterRun']],
|
||||||
|
[Modules::class, Modules::EVENT_INIT, [Events::class, 'onAdminModulesInit']],
|
||||||
|
[ModuleManager::class, ModuleManager::EVENT_AFTER_FILTER_MODULES, [Events::class, 'onAdminModuleManagerAfterFilterModules']],
|
||||||
|
[ModuleControls::class, ModuleControls::EVENT_INIT, [Events::class, 'onAdminModuleControlsInit']],
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
namespace humhub\modules\marketplace\controllers;
|
namespace humhub\modules\marketplace\controllers;
|
||||||
|
|
||||||
use humhub\modules\admin\components\Controller;
|
use humhub\modules\admin\components\Controller;
|
||||||
|
use humhub\modules\admin\permissions\ManageModules;
|
||||||
use humhub\modules\marketplace\Module;
|
use humhub\modules\marketplace\Module;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\web\HttpException;
|
use yii\web\HttpException;
|
||||||
@ -20,74 +21,16 @@ use yii\web\HttpException;
|
|||||||
*/
|
*/
|
||||||
class BrowseController extends Controller
|
class BrowseController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $defaultAction = 'list';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $subLayout = '@admin/views/layouts/module';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public function getAccessRules()
|
public function getAccessRules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['permissions' => \humhub\modules\admin\permissions\ManageModules::class]
|
['permissions' => ManageModules::class]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Complete list of all modules
|
|
||||||
*/
|
|
||||||
public function actionList()
|
|
||||||
{
|
|
||||||
$keyword = Yii::$app->request->post('keyword', "");
|
|
||||||
$categoryId = (int)Yii::$app->request->post('categoryId', 0);
|
|
||||||
$hideInstalled = (boolean)Yii::$app->request->post('hideInstalled');
|
|
||||||
|
|
||||||
// Include Community Modules Form Submit
|
|
||||||
if (!empty(Yii::$app->request->get('communitySwitch'))) {
|
|
||||||
$this->module->settings->set('includeCommunityModules', (empty(Yii::$app->request->post('includeCommunityModules'))) ? 0 : 1);
|
|
||||||
}
|
|
||||||
$includeCommunityModules = (boolean)$this->module->settings->get('includeCommunityModules');
|
|
||||||
|
|
||||||
$onlineModules = $this->module->onlineModuleManager;
|
|
||||||
$modules = $onlineModules->getModules();
|
|
||||||
$categories = $onlineModules->getCategories();
|
|
||||||
|
|
||||||
foreach ($modules as $i => $module) {
|
|
||||||
if (!empty($categoryId) && !in_array($categoryId, $module['categories'])) {
|
|
||||||
unset($modules[$i]);
|
|
||||||
}
|
|
||||||
if (!empty($keyword) && stripos($module['name'], $keyword) === false && stripos($module['description'], $keyword) === false) {
|
|
||||||
unset($modules[$i]);
|
|
||||||
}
|
|
||||||
if ($hideInstalled && Yii::$app->moduleManager->hasModule($module['id'])) {
|
|
||||||
unset($modules[$i]);
|
|
||||||
}
|
|
||||||
if ($this->module->hideLegacyModules && !empty($module['isDeprecated'])) {
|
|
||||||
unset($modules[$i]);
|
|
||||||
}
|
|
||||||
if (!$includeCommunityModules && !empty($module['isCommunity'])) {
|
|
||||||
unset($modules[$i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('list', [
|
|
||||||
'modules' => $modules,
|
|
||||||
'keyword' => $keyword,
|
|
||||||
'categories' => $categories,
|
|
||||||
'categoryId' => $categoryId,
|
|
||||||
'hideInstalled' => $hideInstalled,
|
|
||||||
'includeCommunityModules' => $includeCommunityModules,
|
|
||||||
'licence' => $this->module->getLicence()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the thirdparty disclaimer
|
* Returns the thirdparty disclaimer
|
||||||
|
@ -9,6 +9,7 @@ namespace humhub\modules\marketplace\controllers;
|
|||||||
|
|
||||||
use humhub\modules\admin\components\Controller;
|
use humhub\modules\admin\components\Controller;
|
||||||
use humhub\modules\admin\libs\HumHubAPI;
|
use humhub\modules\admin\libs\HumHubAPI;
|
||||||
|
use humhub\modules\admin\permissions\ManageModules;
|
||||||
use humhub\modules\marketplace\Module;
|
use humhub\modules\marketplace\Module;
|
||||||
use Yii;
|
use Yii;
|
||||||
|
|
||||||
@ -26,18 +27,13 @@ class PurchaseController extends Controller
|
|||||||
*/
|
*/
|
||||||
public $defaultAction = 'list';
|
public $defaultAction = 'list';
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $subLayout = '@admin/views/layouts/module';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public function getAccessRules()
|
public function getAccessRules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['permissions' => \humhub\modules\admin\permissions\ManageModules::class]
|
['permissions' => ManageModules::class]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,18 +43,18 @@ class PurchaseController extends Controller
|
|||||||
public function actionList()
|
public function actionList()
|
||||||
{
|
{
|
||||||
$hasError = false;
|
$hasError = false;
|
||||||
$message = "";
|
$message = '';
|
||||||
|
|
||||||
$licenceKey = Yii::$app->request->post('licenceKey', "");
|
$licenceKey = Yii::$app->request->post('licenceKey', '');
|
||||||
|
|
||||||
if ($licenceKey != "") {
|
if ($licenceKey !== '') {
|
||||||
$result = HumHubAPI::request('v1/modules/registerPaid', ['licenceKey' => $licenceKey]);
|
$result = HumHubAPI::request('v1/modules/registerPaid', ['licenceKey' => $licenceKey]);
|
||||||
if (!isset($result['status'])) {
|
if (!isset($result['status'])) {
|
||||||
$hasError = true;
|
$hasError = true;
|
||||||
$message = 'Could not connect to HumHub API!';
|
$message = 'Could not connect to HumHub API!';
|
||||||
} elseif ($result['status'] == 'ok' || $result['status'] == 'created') {
|
} elseif ($result['status'] == 'ok' || $result['status'] == 'created') {
|
||||||
$message = 'Module licence added!';
|
$message = 'Module licence added!';
|
||||||
$licenceKey = "";
|
$licenceKey = '';
|
||||||
} else {
|
} else {
|
||||||
$hasError = true;
|
$hasError = true;
|
||||||
$message = 'Invalid module licence key!';
|
$message = 'Invalid module licence key!';
|
||||||
@ -75,46 +71,12 @@ class PurchaseController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('list', ['modules' => $modules, 'licenceKey' => $licenceKey, 'hasError' => $hasError, 'message' => $message]);
|
return $this->renderAjax('list', [
|
||||||
}
|
'modules' => $modules,
|
||||||
|
'licenceKey' => $licenceKey,
|
||||||
|
'hasError' => $hasError,
|
||||||
/**
|
'message' => $message,
|
||||||
* Complete list of all modules
|
]);
|
||||||
*/
|
|
||||||
public function actionRegister()
|
|
||||||
{
|
|
||||||
$hasError = false;
|
|
||||||
$message = "";
|
|
||||||
|
|
||||||
$licenceKey = Yii::$app->request->post('licenceKey', "");
|
|
||||||
if ($licenceKey != "") {
|
|
||||||
|
|
||||||
$result = HumHubAPI::request('v1/modules/registerPaid', ['licenceKey' => $licenceKey]);
|
|
||||||
if (!isset($result['status'])) {
|
|
||||||
$hasError = true;
|
|
||||||
$message = 'Could not connect to HumHub API!';
|
|
||||||
} elseif ($result['status'] == 'ok' || $result['status'] == 'created') {
|
|
||||||
$message = 'Module licence added!';
|
|
||||||
$licenceKey = "";
|
|
||||||
} else {
|
|
||||||
$hasError = true;
|
|
||||||
$message = 'Invalid module licence key!';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only showed purchased modules
|
|
||||||
$onlineModules = $this->module->onlineModuleManager;
|
|
||||||
$modules = $onlineModules->getModules(false);
|
|
||||||
|
|
||||||
foreach ($modules as $i => $module) {
|
|
||||||
if (!isset($module['purchased']) || !$module['purchased']) {
|
|
||||||
unset($modules[$i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('list', ['modules' => $modules, 'licenceKey' => $licenceKey, 'hasError' => $hasError, 'message' => $message]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ namespace humhub\modules\marketplace\controllers;
|
|||||||
|
|
||||||
use humhub\components\Module;
|
use humhub\components\Module;
|
||||||
use humhub\modules\admin\components\Controller;
|
use humhub\modules\admin\components\Controller;
|
||||||
|
use humhub\modules\admin\permissions\ManageModules;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\web\HttpException;
|
use yii\web\HttpException;
|
||||||
|
|
||||||
@ -20,42 +21,16 @@ use yii\web\HttpException;
|
|||||||
*/
|
*/
|
||||||
class UpdateController extends Controller
|
class UpdateController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $defaultAction = 'list';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $subLayout = '@admin/views/layouts/module';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public function getAccessRules()
|
public function getAccessRules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['permissions' => \humhub\modules\admin\permissions\ManageModules::class]
|
['permissions' => ManageModules::class]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists all available module updates
|
|
||||||
*/
|
|
||||||
public function actionList()
|
|
||||||
{
|
|
||||||
// Include Community Modules Form Submit
|
|
||||||
if (!empty(Yii::$app->request->get('betaSwitch'))) {
|
|
||||||
$this->module->settings->set('includeBetaUpdates', (empty(Yii::$app->request->post('includeBetaUpdates'))) ? 0 : 1);
|
|
||||||
}
|
|
||||||
$includeBetaUpdates = (boolean)$this->module->settings->get('includeBetaUpdates');
|
|
||||||
|
|
||||||
$modules = $this->module->onlineModuleManager->getModuleUpdates(false);
|
|
||||||
return $this->render('list', ['modules' => $modules, 'includeBetaUpdates' => $includeBetaUpdates]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a module with the most recent version online
|
* Updates a module with the most recent version online
|
||||||
*
|
*
|
||||||
@ -82,23 +57,30 @@ class UpdateController extends Controller
|
|||||||
|
|
||||||
if (empty($moduleInfo['latestCompatibleVersion']['downloadUrl'])) {
|
if (empty($moduleInfo['latestCompatibleVersion']['downloadUrl'])) {
|
||||||
if (!empty($moduleInfo['isPaid'])) {
|
if (!empty($moduleInfo['isPaid'])) {
|
||||||
$this->view->setStatusMessage('error', Yii::t('AdminModule.modules', 'License not found or expired. Please contact the module publisher.'));
|
$error = Yii::t('AdminModule.modules', 'License not found or expired. Please contact the module publisher.');
|
||||||
} else {
|
} else {
|
||||||
Yii::error('Could not determine module download url from HumHub API response.', 'marketplace');
|
$error = 'Could not determine module download url from HumHub API response.';
|
||||||
|
Yii::error($error, 'marketplace');
|
||||||
}
|
}
|
||||||
return $this->redirect(['/marketplace/update/list']);
|
throw new HttpException(500, $error);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->module->onlineModuleManager->update($moduleId);
|
$this->module->onlineModuleManager->update($moduleId);
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$module->publishAssets(true);
|
$module->publishAssets(true);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Yii::error($e);
|
Yii::error($e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->redirect(['/marketplace/update/list']);
|
return $this->asJson([
|
||||||
|
'success' => true,
|
||||||
|
'status' => Yii::t('AdminModule.modules', 'Update successful'),
|
||||||
|
'message' => Yii::t('AdminModule.modules', 'Module "{moduleName}" has been updated to version {newVersion} successfully.', [
|
||||||
|
'moduleName' => $moduleInfo['latestCompatibleVersion']['name'],
|
||||||
|
'newVersion' => $moduleInfo['latestCompatibleVersion']['version'],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
184
protected/humhub/modules/marketplace/models/Module.php
Normal file
184
protected/humhub/modules/marketplace/models/Module.php
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\marketplace\models;
|
||||||
|
|
||||||
|
use humhub\modules\marketplace\Module as MarketplaceModule;
|
||||||
|
use Yii;
|
||||||
|
use yii\base\Model;
|
||||||
|
use yii\helpers\Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Module for not installed module
|
||||||
|
* Used in order to initialise module data from array
|
||||||
|
*
|
||||||
|
* @property-read string $version
|
||||||
|
* @property-read string $image
|
||||||
|
* @property-read string $checkoutUrl
|
||||||
|
* @property-read bool $isNonFree
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
*/
|
||||||
|
class Module extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $latestVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $moduleImageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $professional_only;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $useCases;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $featured;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $showDisclaimer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $isThirdParty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $isCommunity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $isPartner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $isDeprecated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $marketplaceUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $latestCompatibleVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $price_eur;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $categories;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $purchased;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $price_request_quote;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $checkoutUrl;
|
||||||
|
|
||||||
|
public function __construct($config = [])
|
||||||
|
{
|
||||||
|
foreach ($config as $name => $value) {
|
||||||
|
if (!property_exists($this, $name)) {
|
||||||
|
// Exclude new unknown property from marketplace API to avoid error
|
||||||
|
unset($config[$name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsNonFree(): bool
|
||||||
|
{
|
||||||
|
return (!empty($this->price_eur) || !empty($this->price_request_quote));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVersion(): string
|
||||||
|
{
|
||||||
|
return $this->latestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImage(): string
|
||||||
|
{
|
||||||
|
return empty($this->moduleImageUrl)
|
||||||
|
? Yii::getAlias('@web-static/img/default_module.jpg')
|
||||||
|
: $this->moduleImageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isInstalled(): bool
|
||||||
|
{
|
||||||
|
return Yii::$app->moduleManager->hasModule($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isProFeature(): bool
|
||||||
|
{
|
||||||
|
return !empty($this->professional_only);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isProOnly(): bool
|
||||||
|
{
|
||||||
|
if (!$this->isProFeature()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var MarketplaceModule */
|
||||||
|
$marketplaceModule = Yii::$app->getModule('marketplace');
|
||||||
|
$licence = $marketplaceModule->getLicence();
|
||||||
|
|
||||||
|
return $licence->type !== Licence::LICENCE_TYPE_PRO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCheckoutUrl(): string
|
||||||
|
{
|
||||||
|
return str_replace('-returnToUrl-', Url::to(['/marketplace/purchase/list'], true), $this->checkoutUrl);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
@media (min-width:500px){.container-modules.container-fluid .container-module-updates .card{width:33.33333333%}}@media (min-width:1000px){.container-modules.container-fluid .container-module-updates .card{width:25%}}@media (min-width:1300px){.container-modules.container-fluid .container-module-updates .card{width:20%}}@media (min-width:1600px){.container-modules.container-fluid .container-module-updates .card{width:16.66666667%}}@media (min-width:1900px){.container-modules.container-fluid .container-module-updates .card{width:12.5%}}.container-module-updates{background:#02A1B1;margin-top:30px;padding:16px 10px 2px;border-radius:4px}.container-module-updates .row.cards{margin-right:-1px;margin-top:0}.container-module-updates .modules-type{color:#FFFFFF;margin:10px 0 30px}.container-module-updates .card{padding-right:1px}.container-module-updates .card .card-panel{color:#FFF;margin-top:0}.container-module-updates .card .card-panel>div:not(.card-status){background:#02717c}.container-module-updates .card .card-panel .card-header{padding:12px}.container-module-updates .card .card-panel .card-body{padding:4px 12px 20px;color:#FFF}.container-module-updates .card .card-panel .card-body .card-title{color:#FFF;font-size:14px}.container-module-updates .card .card-panel .card-footer{padding:0 12px 12px}.container-module-updates .card .card-panel .card-footer .btn-info{border-radius:4px}.container-module-updates .card .card-panel .card-footer .btn-info.active{border-color:#FFF}.container-module-updates .card .card-panel .card-footer .btn-info:not(.active){padding:0 4px;border:1px solid #FFF;background:#02717c;color:#FFF}.container-module-updates .card .card-panel .card-footer .btn-info:not(.active):hover,.container-module-updates .card .card-panel .card-footer .btn-info:not(.active):active{background:#047c88 !important;color:#FFF !important}.container-module-updates .card .card-panel .card-footer .btn-info[data-update-status=failed]{border-color:#fc314f}/*# sourceMappingURL=modules.css.map */
|
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["modules.less"],"names":[],"mappings":"AAEQ,QAA0B,iBAA1B,kBAFU,gBACd,0BAEQ,OACI,oBAGR,QAA2B,kBAA3B,kBAPU,gBACd,0BAOQ,OACI,WAGR,QAA2B,kBAA3B,kBAZU,gBACd,0BAYQ,OACI,WAGR,QAA2B,kBAA3B,kBAjBU,gBACd,0BAiBQ,OACI,oBAGR,QAA2B,kBAA3B,kBAtBU,gBACd,0BAsBQ,OACI,aAQhB,0BACI,kBAAA,CACA,eAAA,CACA,qBAAA,CACA,kBAJJ,yBAKI,KAAI,OACA,iBAAA,CACA,aAPR,yBASI,eACI,aAAA,CACA,mBAXR,yBAaI,OACI,kBAdR,yBAaI,MAEI,aACI,UAAA,CACA,aAjBZ,yBAaI,MAEI,YAGI,IAAK,IAAI,eACL,mBAnBhB,yBAaI,MAEI,YAMI,cACI,aAtBhB,yBAaI,MAEI,YASI,YACI,qBAAA,CACA,WA1BhB,yBAaI,MAEI,YASI,WAGI,aACI,UAAA,CACA,eA7BpB,yBAaI,MAEI,YAiBI,cACI,oBAjChB,yBAaI,MAEI,YAiBI,aAEI,WACI,kBACA,yBAvBhB,MAEI,YAiBI,aAEI,UAEK,QACG,kBAEJ,yBA1BhB,MAEI,YAiBI,aAEI,UAKK,IAAI,UACD,aAAA,CACA,qBAAA,CACA,kBAAA,CACA,WACA,yBA/BpB,MAEI,YAiBI,aAEI,UAKK,IAAI,SAKA,OAAQ,yBA/B7B,MAEI,YAiBI,aAEI,UAKK,IAAI,SAKS,QACN,kBAAA,YACA,UAAA,YAGR,yBApChB,MAEI,YAiBI,aAEI,UAeK,4BACG","file":"modules.css"}
|
@ -0,0 +1,89 @@
|
|||||||
|
.container-modules.container-fluid {
|
||||||
|
.container-module-updates {
|
||||||
|
@media (min-width: 500px) {
|
||||||
|
.card {
|
||||||
|
width: 33.33333333%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1000px) {
|
||||||
|
.card {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1300px) {
|
||||||
|
.card {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1600px) {
|
||||||
|
.card {
|
||||||
|
width: 16.66666667%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 1900px) {
|
||||||
|
.card {
|
||||||
|
width: 12.5%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@moduleUpdateLayoutBg: #02A1B1;
|
||||||
|
@moduleUpdateCardBg: #02717c;
|
||||||
|
.container-module-updates {
|
||||||
|
background: @moduleUpdateLayoutBg;
|
||||||
|
margin-top: 30px;
|
||||||
|
padding: 16px 10px 2px;
|
||||||
|
border-radius: 4px;
|
||||||
|
.row.cards {
|
||||||
|
margin-right: -1px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.modules-type {
|
||||||
|
color: #FFFFFF;
|
||||||
|
margin: 10px 0 30px;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
padding-right: 1px;
|
||||||
|
.card-panel {
|
||||||
|
color: #FFF;
|
||||||
|
margin-top: 0;
|
||||||
|
> div:not(.card-status) {
|
||||||
|
background: @moduleUpdateCardBg;
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.card-body {
|
||||||
|
padding: 4px 12px 20px;
|
||||||
|
color: #FFF;
|
||||||
|
.card-title {
|
||||||
|
color: #FFF;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.card-footer {
|
||||||
|
padding: 0 12px 12px;
|
||||||
|
.btn-info {
|
||||||
|
border-radius: 4px;
|
||||||
|
&.active {
|
||||||
|
border-color: #FFF;
|
||||||
|
}
|
||||||
|
&:not(.active) {
|
||||||
|
padding: 0 4px;
|
||||||
|
border: 1px solid #FFF;
|
||||||
|
background: @moduleUpdateCardBg;
|
||||||
|
color: #FFF;
|
||||||
|
&:hover, &:active {
|
||||||
|
background: #047c88 !important;
|
||||||
|
color: #FFF !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&[data-update-status=failed] {
|
||||||
|
border-color: #fc314f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
humhub.module('marketplace', function (module, require, $) {
|
||||||
|
const client = require('client');
|
||||||
|
const loader = require('ui.loader');
|
||||||
|
const status = require('ui.status');
|
||||||
|
|
||||||
|
const update = function (evt) {
|
||||||
|
startUpdate(evt);
|
||||||
|
|
||||||
|
client.post(evt).then(function (response) {
|
||||||
|
endSuccessUpdate(evt, response);
|
||||||
|
}).catch(function (err) {
|
||||||
|
endFailedUpdate(evt, err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const startUpdate = function(evt) {
|
||||||
|
const card = evt.$trigger.closest('.card');
|
||||||
|
card.css({width: card.outerWidth(), height: card.outerHeight()});
|
||||||
|
evt.$trigger.parent().hide();
|
||||||
|
evt.$trigger.removeAttr('data-update-status');
|
||||||
|
loader.set(evt.$trigger.parent().prev(), {size: '12px'});
|
||||||
|
}
|
||||||
|
|
||||||
|
const endSuccessUpdate = function (evt, response) {
|
||||||
|
const card = evt.$trigger.closest('.card');
|
||||||
|
const body = card.find('.card-body');
|
||||||
|
|
||||||
|
body.html('<div class="text-center"><span class="fa fa-check"></span></div>');
|
||||||
|
const resultIcon = body.find('.fa').css({fontSize: 0, opacity: 0});
|
||||||
|
resultIcon.animate({fontSize: '50px', opacity: 1}, 1000, function () {
|
||||||
|
$(this).after('<div style="padding-top:20px">' + response.status + '</div>');
|
||||||
|
setTimeout(function () {
|
||||||
|
card.css({
|
||||||
|
position: 'absolute',
|
||||||
|
top: card.position().top,
|
||||||
|
left: card.position().left,
|
||||||
|
});
|
||||||
|
|
||||||
|
card.after('<div class="' + card.attr('class') + '"><div class="card-panel"></div></div>');
|
||||||
|
card.next()
|
||||||
|
.css({opacity: 0, minHeight: card.outerHeight()})
|
||||||
|
.animate({width: 0}, 'slow', function () {$(this).remove()});
|
||||||
|
card.animate({opacity: 0}, 'slow', function () {
|
||||||
|
$(this).remove();
|
||||||
|
const availableUpdates = $('[data-action-click="marketplace.update"]').length;
|
||||||
|
$('.group-modules-count-availableUpdates').html(availableUpdates);
|
||||||
|
if (availableUpdates === 0) {
|
||||||
|
$('[data-action-click="marketplace.updateAll"]').remove();
|
||||||
|
$('.container-module-updates').animate({opacity: 0, height: 0, padding: 0, margin: 0}, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.log.success('success.saved', true);
|
||||||
|
status.success(response.message);
|
||||||
|
evt.$trigger.attr('data-update-status', 'success');
|
||||||
|
|
||||||
|
runNextUpdate();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const endFailedUpdate = function(evt, response) {
|
||||||
|
module.log.error(response);
|
||||||
|
status.error(response.message);
|
||||||
|
evt.$trigger.attr('data-update-status', 'failed')
|
||||||
|
.attr('title', response.message);
|
||||||
|
|
||||||
|
evt.$trigger.parent().show();
|
||||||
|
loader.reset(evt.$trigger.parent().prev());
|
||||||
|
|
||||||
|
runNextUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateAll = function (evt) {
|
||||||
|
const btn = evt.$trigger;
|
||||||
|
|
||||||
|
if (btn.data('is-updating-all')) {
|
||||||
|
stopUpdateAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.data('is-updating-all', true)
|
||||||
|
.data('orig-title', btn.html())
|
||||||
|
.data('orig-class', btn.attr('class'))
|
||||||
|
.html(btn.data('stop-title'))
|
||||||
|
.attr('class', btn.data('stop-class'));
|
||||||
|
|
||||||
|
$('[data-action-click="marketplace.update"]').removeAttr('data-update-status');
|
||||||
|
|
||||||
|
runNextUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
const runNextUpdate = function() {
|
||||||
|
const updateAllButton = $('[data-action-click="marketplace.updateAll"]');
|
||||||
|
if (!updateAllButton.data('is-updating-all')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextButton = $('[data-action-click="marketplace.update"]:not([data-update-status=failed]):first');
|
||||||
|
if (nextButton.length) {
|
||||||
|
nextButton.click();
|
||||||
|
} else {
|
||||||
|
stopUpdateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopUpdateAll = function () {
|
||||||
|
const updateAllButton = $('[data-action-click="marketplace.updateAll"]');
|
||||||
|
updateAllButton.data('is-updating-all', false)
|
||||||
|
.html(updateAllButton.data('orig-title'))
|
||||||
|
.attr('class', updateAllButton.data('orig-class'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerLicenceKey = function(evt) {
|
||||||
|
const form = evt.$trigger.closest('form');
|
||||||
|
const licenceKey = form.find('input[name=licenceKey]').val();
|
||||||
|
|
||||||
|
loader.set(form);
|
||||||
|
|
||||||
|
client.post(form.attr('action'), {data: {licenceKey}}).then(function (response) {
|
||||||
|
form.closest('.modal-dialog').after(response.html).remove();
|
||||||
|
}).catch(function (err) {
|
||||||
|
module.log.error(err);
|
||||||
|
status.error(err.message);
|
||||||
|
loader.reset(form);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.export({
|
||||||
|
update,
|
||||||
|
updateAll,
|
||||||
|
registerLicenceKey,
|
||||||
|
});
|
||||||
|
});
|
@ -1,105 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use humhub\modules\marketplace\models\Licence;
|
|
||||||
use humhub\modules\ui\view\components\View;
|
|
||||||
use yii\helpers\Url;
|
|
||||||
use yii\helpers\Html;
|
|
||||||
|
|
||||||
/* @var $licence Licence */
|
|
||||||
/* @var $module array */
|
|
||||||
/* @var $view View */
|
|
||||||
|
|
||||||
$isInstalled = (Yii::$app->moduleManager->hasModule($module['id']));
|
|
||||||
|
|
||||||
$moduleImageUrl = Yii::getAlias('@web-static/img/default_module.jpg');
|
|
||||||
if (isset($module['moduleImageUrl']) && $module['moduleImageUrl'] != "") {
|
|
||||||
$moduleImageUrl = $module['moduleImageUrl'];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$isProFeature = (!empty($module['professional_only']));
|
|
||||||
$isProOnly = ($isProFeature && $licence->type !== Licence::LICENCE_TYPE_PRO);
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<div class="media <?php if ($isInstalled || $isProOnly): ?>module-installed<?php endif; ?>">
|
|
||||||
<img class="media-object img-rounded pull-left" data-src="holder.js/64x64" alt="64x64"
|
|
||||||
style="width: 64px; height: 64px;" src="<?= $moduleImageUrl; ?>">
|
|
||||||
|
|
||||||
<div class="media-body">
|
|
||||||
|
|
||||||
<h4 class="media-heading">
|
|
||||||
<?= $module['name']; ?>
|
|
||||||
|
|
||||||
<?php if (!empty($module['featured'])): ?>
|
|
||||||
<i class="fa fa-star text-info" aria-hidden="true"></i>
|
|
||||||
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if ($isProFeature): ?>
|
|
||||||
<a href="<?= Url::to(['/admin/information']) ?>">
|
|
||||||
<span class="badge badge-danger pull-right"
|
|
||||||
style="font-size:12px;line-height:18px;background-color:#3F4B5A;color:white">
|
|
||||||
<?php if ($isProOnly): ?><i class="fa fa-lock"></i><?php endif; ?>
|
|
||||||
Professional Edition Feature
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<?php endif; ?>
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<p><?= $module['description']; ?></p>
|
|
||||||
|
|
||||||
<div class="module-controls">
|
|
||||||
<?= Yii::t('MarketplaceModule.base', 'Latest version:'); ?> <?= $module['latestVersion']; ?>
|
|
||||||
|
|
||||||
<?php if ($isInstalled): ?>
|
|
||||||
· <?= Yii::t('MarketplaceModule.base', 'Installed'); ?>
|
|
||||||
</span>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (isset($module['purchased']) && $module['purchased']) : ?>
|
|
||||||
Purchased
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (isset($module['latestCompatibleVersion'])) : ?>
|
|
||||||
|
|
||||||
<?php if ($module['latestCompatibleVersion'] != $module['latestVersion']) : ?>
|
|
||||||
· <?= Yii::t('MarketplaceModule.base', 'Latest compatible version:'); ?> <?= $module['latestCompatibleVersion']; ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (!$isInstalled): ?>
|
|
||||||
<?php if ($isProOnly): ?>
|
|
||||||
· <?= Html::a('<i class="fa fa-lock"></i> Professional Edition', ['/admin/information'], ['style' => 'font-weight:bold']); ?>
|
|
||||||
<?php elseif (!empty($module['price_request_quote']) && !$module['purchased']) : ?>
|
|
||||||
<?php $checkoutUrl = str_replace('-returnToUrl-', Url::to(['/marketplace/purchase/list'], true), $module['checkoutUrl']); ?>
|
|
||||||
· <?= Html::a(Yii::t('MarketplaceModule.base', 'Buy'), $checkoutUrl, ['style' => 'font-weight:bold', 'target' => '_blank']); ?>
|
|
||||||
<?php elseif (!empty($module['price_eur']) && !$module['purchased']) : ?>
|
|
||||||
<?php $checkoutUrl = str_replace('-returnToUrl-', Url::to(['/marketplace/purchase/list'], true), $module['checkoutUrl']); ?>
|
|
||||||
· <?= Html::a(Yii::t('MarketplaceModule.base', 'Buy (%price%)', ['%price%' => $module['price_eur'] . '€']), $checkoutUrl, ['style' => 'font-weight:bold', 'target' => '_blank']); ?>
|
|
||||||
<?php else: ?>
|
|
||||||
· <?= Html::a(Yii::t('MarketplaceModule.base', 'Install'), Url::to(['/marketplace/browse/install', 'moduleId' => $module['id']]), ['style' => 'font-weight:bold', 'data-loader' => "modal", 'data-message' => Yii::t('MarketplaceModule.base', 'Installing module...'), 'data-method' => 'POST']); ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php else : ?>
|
|
||||||
· <span
|
|
||||||
style="color:red"><?= Yii::t('MarketplaceModule.base', 'No compatible module version found!'); ?></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
· <?= Html::a(Yii::t('MarketplaceModule.base', 'More info') .
|
|
||||||
' <i class="fa fa-external-link" aria-hidden="true"></i>'
|
|
||||||
, $module['marketplaceUrl'], ['target' => '_blank']); ?>
|
|
||||||
|
|
||||||
<?php if (!empty($module['isThirdParty'])): ?>
|
|
||||||
· <?= Html::a(Yii::t('MarketplaceModule.base', 'Third-party'), Url::to(['thirdparty-disclaimer']), ['data-target' => '#globalModal']); ?>
|
|
||||||
<?php if (!empty($module['isCommunity'])): ?>
|
|
||||||
<a href="<?= Url::to(['thirdparty-disclaimer']) ?>" data-target="#globalModal">
|
|
||||||
- Community
|
|
||||||
</a>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,62 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use yii\helpers\Url;
|
|
||||||
use humhub\libs\Html;
|
|
||||||
|
|
||||||
/* @var $this View */
|
|
||||||
/* @var $modules array */
|
|
||||||
/* @var $categoryId int */
|
|
||||||
/* @var $keyword string */
|
|
||||||
/* @var $includeCommunityModules boolean */
|
|
||||||
|
|
||||||
?>
|
|
||||||
<div class="panel-body">
|
|
||||||
|
|
||||||
<?= Html::beginForm(Url::to(['/marketplace/browse']), 'post', ['class' => 'form-search', 'id' => 'filterForm']); ?>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<?= Html::dropDownList('categoryId', $categoryId, $categories, ['class' => 'form-control', 'data-ui-select2' => '', 'id' => 'categorySelect']); ?>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-group form-group-search">
|
|
||||||
<?= Html::textInput("keyword", $keyword, ["class" => "form-control form-search", "placeholder" => Yii::t('MarketplaceModule.base', 'search for available modules online')]); ?>
|
|
||||||
<?= Html::submitButton(Yii::t('MarketplaceModule.base', 'Search'), ['class' => 'btn btn-default btn-sm form-button-search', 'data-ui-loader' => ""]); ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?= Html::endForm(); ?>
|
|
||||||
|
|
||||||
<?= Html::beginForm(Url::to(['/marketplace/browse', 'communitySwitch' => 1]), 'post', ['id' => 'communityForm']); ?>
|
|
||||||
<div class="form-group pull-right">
|
|
||||||
<label>
|
|
||||||
<?= Html::checkbox('includeCommunityModules', $includeCommunityModules, ['id' => 'chkCommunity']); ?>
|
|
||||||
<?= Yii::t('MarketplaceModule.base', 'Include Community Modules'); ?>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<?= Html::endForm(); ?>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<?php if (count($modules) == 0) : ?>
|
|
||||||
|
|
||||||
<div class="text-center">
|
|
||||||
<em><?= Yii::t('MarketplaceModule.base', 'No modules found!'); ?></em>
|
|
||||||
<br><br>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
<?php foreach ($modules as $module): ?>
|
|
||||||
<?= $this->render('_module', ['module' => $module, 'licence' => $licence]); ?>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script <?= Html::nonce(); ?>>
|
|
||||||
$('#categorySelect').change(function () {
|
|
||||||
$('#filterForm').submit();
|
|
||||||
});
|
|
||||||
$('#chkCommunity').change(function () {
|
|
||||||
$('#communityForm').submit();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
@ -1,76 +1,92 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\modules\marketplace\assets\Assets;
|
||||||
|
use humhub\widgets\Button;
|
||||||
|
use yii\base\View;
|
||||||
use yii\helpers\Url;
|
use yii\helpers\Url;
|
||||||
use yii\helpers\Html;
|
use yii\helpers\Html;
|
||||||
|
|
||||||
|
/* @var Module[] $modules */
|
||||||
|
/* @var string $licenceKey */
|
||||||
|
/* @var bool $hasError */
|
||||||
|
/* @var string $message */
|
||||||
|
/* @var View $this */
|
||||||
|
|
||||||
|
Assets::register($this);
|
||||||
?>
|
?>
|
||||||
|
<div class="modal-dialog modal-dialog-normal animated fadeIn">
|
||||||
<div class="panel-body">
|
<div class="modal-content">
|
||||||
<!-- search form -->
|
<div class="modal-header">
|
||||||
<?= Html::beginForm(Url::to(['/marketplace/purchase/list']), 'post', ['class' => 'form-search']); ?>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
<div class="row">
|
<h4 class="modal-title" id="myModalLabel">
|
||||||
<div class="col-md-3"></div>
|
<?= Yii::t('MarketplaceModule.base', 'Add Licence Key'); ?>
|
||||||
<div class="col-md-6">
|
</h4>
|
||||||
<div class="form-group form-group-search">
|
|
||||||
<?= Html::textInput("licenceKey", $licenceKey, ["class" => "form-control form-search", "placeholder" => Yii::t('MarketplaceModule.base', 'Add purchased module by licence key')]); ?>
|
|
||||||
<?= Html::submitButton(Yii::t('MarketplaceModule.base', 'Register'), ['class' => 'btn btn-default btn-sm form-button-search', 'data-ui-loader' => ""]); ?>
|
|
||||||
</div>
|
|
||||||
<?php if ($message != ""): ?>
|
|
||||||
<div style="color:<?= ($hasError) ? 'red' : 'green'; ?>"><?= Html::encode($message); ?></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3"></div>
|
<div class="modal-body">
|
||||||
</div>
|
|
||||||
<?= Html::endForm(); ?>
|
|
||||||
|
|
||||||
<br/>
|
<!-- search form -->
|
||||||
|
<?= Html::beginForm(Url::to(['/marketplace/purchase']), 'post', ['class' => 'form-search']); ?>
|
||||||
<?php if (count($modules) == 0) : ?>
|
<div class="row">
|
||||||
<div class="text-center">
|
<div class="col-md-12">
|
||||||
<em><?= Yii::t('MarketplaceModule.base', 'No purchased modules found!'); ?></em>
|
<div class="form-group form-group-search">
|
||||||
<br><br>
|
<?= Html::textInput('licenceKey', $licenceKey, ['class' => 'form-control form-search', 'placeholder' => Yii::t('MarketplaceModule.base', 'Add purchased module by licence key')]); ?>
|
||||||
</div>
|
<?= Button::defaultType(Yii::t('MarketplaceModule.base', 'Register'))
|
||||||
<?php else: ?>
|
->submit()
|
||||||
|
->action('marketplace.registerLicenceKey')
|
||||||
|
->cssClass('btn btn-default btn-sm form-button-search'); ?>
|
||||||
<?php foreach ($modules as $module): ?>
|
|
||||||
<hr>
|
|
||||||
<div class="media ">
|
|
||||||
|
|
||||||
<?php
|
|
||||||
$moduleImageUrl = Yii::getAlias('@web-static/img/default_module.jpg');
|
|
||||||
if (isset($module['moduleImageUrl']) && $module['moduleImageUrl'] != "") {
|
|
||||||
$moduleImageUrl = $module['moduleImageUrl'];
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<img class="media-object img-rounded pull-left" data-src="holder.js/64x64" alt="64x64"
|
|
||||||
style="width: 64px; height: 64px;" src="<?= $moduleImageUrl; ?>">
|
|
||||||
|
|
||||||
<div class="media-body">
|
|
||||||
<h4 class="media-heading"><?= $module['name']; ?>
|
|
||||||
<?php if (Yii::$app->moduleManager->hasModule($module['id'])): ?>
|
|
||||||
<small><span
|
|
||||||
class="label label-info"><?= Yii::t('MarketplaceModule.base', 'Installed'); ?>
|
|
||||||
</small></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</h4>
|
|
||||||
<p><?= $module['description']; ?></p>
|
|
||||||
|
|
||||||
<div class="module-controls">
|
|
||||||
<?php if (!Yii::$app->moduleManager->hasModule($module['id'])): ?>
|
|
||||||
<?= Html::a(Yii::t('MarketplaceModule.base', 'Install'), Url::to(['/marketplace/browse/install', 'moduleId' => $module['id']]), ['style' => 'font-weight:bold', 'data-loader' => "modal", 'data-message' => Yii::t('MarketplaceModule.base', 'Installing module...'), 'data-method' => 'POST']); ?>
|
|
||||||
·
|
|
||||||
<?php endif; ?>
|
|
||||||
<?= Html::a(Yii::t('MarketplaceModule.base', 'More info'), $module['marketplaceUrl'], ['target' => '_blank']); ?>
|
|
||||||
· <?= Yii::t('MarketplaceModule.base', 'Latest version:'); ?> <?= $module['latestVersion']; ?>
|
|
||||||
· <?= Yii::t('MarketplaceModule.base', 'Licence Key:'); ?> <?= $module['licence_key']; ?>
|
|
||||||
</div>
|
</div>
|
||||||
|
<?php if ($message != ''): ?>
|
||||||
|
<div style="color:<?= ($hasError) ? 'red' : 'green'; ?>"><?= Html::encode($message); ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-3"></div>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?= Html::endForm(); ?>
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<small class="pull-right"><br />Installation
|
<br/>
|
||||||
Id: <?= Yii::$app->getModule('admin')->settings->get('installationId'); ?></small>
|
|
||||||
|
<?php if (empty($modules)) : ?>
|
||||||
|
<div class="text-center">
|
||||||
|
<em><?= Yii::t('MarketplaceModule.base', 'No purchased modules found!'); ?></em>
|
||||||
|
<br><br>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<?php foreach ($modules as $module): ?>
|
||||||
|
<hr>
|
||||||
|
<div class="media">
|
||||||
|
<img class="media-object img-rounded pull-left" data-src="holder.js/64x64" alt="64x64"
|
||||||
|
style="width: 64px; height: 64px;"
|
||||||
|
src="<?= empty($module['moduleImageUrl']) ? Yii::getAlias('@web-static/img/default_module.jpg') : $module['moduleImageUrl']; ?>">
|
||||||
|
|
||||||
|
<div class="media-body">
|
||||||
|
<h4 class="media-heading"><?= $module['name']; ?>
|
||||||
|
<?php if (Yii::$app->moduleManager->hasModule($module['id'])): ?>
|
||||||
|
<small><span
|
||||||
|
class="label label-info"><?= Yii::t('MarketplaceModule.base', 'Installed'); ?>
|
||||||
|
</span></small>
|
||||||
|
<?php endif; ?>
|
||||||
|
</h4>
|
||||||
|
<p><?= $module['description']; ?></p>
|
||||||
|
|
||||||
|
<div class="module-controls">
|
||||||
|
<?php if (!Yii::$app->moduleManager->hasModule($module['id'])): ?>
|
||||||
|
<?= Html::a(Yii::t('MarketplaceModule.base', 'Install'), Url::to(['/marketplace/browse/install', 'moduleId' => $module['id']]), ['style' => 'font-weight:bold', 'data-loader' => "modal", 'data-message' => Yii::t('MarketplaceModule.base', 'Installing module...'), 'data-method' => 'POST']); ?>
|
||||||
|
·
|
||||||
|
<?php endif; ?>
|
||||||
|
<?= Html::a(Yii::t('MarketplaceModule.base', 'More info'), $module['marketplaceUrl'], ['target' => '_blank']); ?>
|
||||||
|
· <?= Yii::t('MarketplaceModule.base', 'Latest version:'); ?> <?= $module['latestVersion']; ?>
|
||||||
|
· <?= Yii::t('MarketplaceModule.base', 'Licence Key:'); ?> <?= $module['licence_key']; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<small class="pull-right"><br />Installation Id: <?= Yii::$app->getModule('admin')->settings->get('installationId'); ?></small>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use humhub\modules\ui\icon\widgets\Icon;
|
|
||||||
use humhub\libs\Html;
|
|
||||||
use yii\helpers\Url;
|
|
||||||
|
|
||||||
/* @var $modules [] */
|
|
||||||
|
|
||||||
?>
|
|
||||||
<div class="panel-body">
|
|
||||||
<?= Html::beginForm(Url::to(['/marketplace/update', 'betaSwitch' => 1]), 'post', ['id' => 'betaSwitchForm']); ?>
|
|
||||||
<div class="form-group pull-right">
|
|
||||||
<label>
|
|
||||||
<?= Html::checkbox('includeBetaUpdates', $includeBetaUpdates, ['id' => 'chkBeta']); ?>
|
|
||||||
<?= Yii::t('MarketplaceModule.base', 'Include beta updates'); ?>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<?= Html::endForm(); ?>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<?php if (empty($modules)): ?>
|
|
||||||
<br>
|
|
||||||
<div
|
|
||||||
class="alert alert-success"><?= Icon::get('check') ?> <?= Yii::t('MarketplaceModule.base', 'All modules are up to date!'); ?></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php foreach ($modules as $module): ?>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
$moduleImageUrl = Yii::getAlias('@web-static/img/default_module.jpg');
|
|
||||||
if (!empty($module['moduleImageUrl'])) {
|
|
||||||
$moduleImageUrl = $module['moduleImageUrl'];
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<div class="media">
|
|
||||||
<img class="media-object img-rounded pull-left" data-src="holder.js/64x64" alt="64x64"
|
|
||||||
style="width: 64px; height: 64px;" src="<?= $moduleImageUrl; ?>">
|
|
||||||
|
|
||||||
<div class="media-body">
|
|
||||||
<h4 class="media-heading"><?= $module['name']; ?> </h4>
|
|
||||||
|
|
||||||
<?php if (isset($module['latestCompatibleVersion']) && Yii::$app->moduleManager->hasModule($module['id'])) : ?>
|
|
||||||
<?= Html::a('<i class="fa fa-download"> </i> ' . Yii::t('MarketplaceModule.base', 'Update'), ['/marketplace/update/install', 'moduleId' => $module['id']], ['class' => 'pull-right btn btn-success btn-sm', 'data-loader' => "modal", 'data-message' => Yii::t('MarketplaceModule.base', 'Updating module...'), 'data-method' => 'POST']); ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
<p><?= $module['description']; ?></p>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="module-controls">
|
|
||||||
<?php if (isset($module['latestCompatibleVersion']) && Yii::$app->moduleManager->hasModule($module['id'])) : ?>
|
|
||||||
<?= Yii::t('MarketplaceModule.base', 'Installed version:'); ?> <?= Yii::$app->moduleManager->getModule($module['id'])->getVersion(); ?>
|
|
||||||
· <?= Yii::t('MarketplaceModule.base', 'Latest compatible Version:'); ?> <?= $module['latestCompatibleVersion']; ?>
|
|
||||||
· <?= Html::a(Yii::t('MarketplaceModule.base', 'View Changelog'), $module['marketplaceUrl'] . '#changelog', ['target' => '_blank']); ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script <?= Html::nonce(); ?>>
|
|
||||||
$('#chkBeta').change(function () {
|
|
||||||
$('#betaSwitchForm').submit();
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\marketplace\widgets;
|
||||||
|
|
||||||
|
use humhub\components\Widget;
|
||||||
|
use humhub\modules\marketplace\models\Module;
|
||||||
|
use humhub\modules\ui\icon\widgets\Icon;
|
||||||
|
use humhub\widgets\Button;
|
||||||
|
use Yii;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleInstallActionButtons shows actions for not installed module
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class ModuleInstallActionButtons extends Widget
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Module
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Template for buttons
|
||||||
|
*/
|
||||||
|
public $template = '<div class="card-footer text-right">{buttons}</div>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
if (!isset($this->module->latestCompatibleVersion) || $this->module->isInstalled()) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->module->isProOnly()) {
|
||||||
|
$html .= Button::primary(Icon::get('info-circle') . ' ' . Yii::t('MarketplaceModule.base', 'Professional Edition'))
|
||||||
|
->link(['/admin/information'])
|
||||||
|
->sm()
|
||||||
|
->loader(false)
|
||||||
|
->tooltip(Yii::t('MarketplaceModule.base', 'This is a Professional Edition module. You do not have the permission to install this module. If you are interested in our product, you can find more information about our Professional Edition by clicking on this button.'));
|
||||||
|
} elseif (!empty($this->module->price_request_quote) && !$this->module->purchased) {
|
||||||
|
$html .= Button::primary(Yii::t('MarketplaceModule.base', 'Buy'))
|
||||||
|
->link($this->module->checkoutUrl)
|
||||||
|
->sm()
|
||||||
|
->options(['target' => '_blank'])
|
||||||
|
->loader(false);
|
||||||
|
} elseif (!empty($this->module->price_eur) && !$this->module->purchased) {
|
||||||
|
$html .= Button::primary(Yii::t('MarketplaceModule.base', 'Buy (%price%)', ['%price%' => $this->module->price_eur . '€']))
|
||||||
|
->link($this->module->checkoutUrl)
|
||||||
|
->sm()
|
||||||
|
->options(['target' => '_blank'])
|
||||||
|
->loader(false);
|
||||||
|
} else {
|
||||||
|
$html .= Button::primary(Yii::t('MarketplaceModule.base', 'Install'))
|
||||||
|
->link(['/marketplace/browse/install', 'moduleId' => $this->module->id])
|
||||||
|
->sm()
|
||||||
|
->options([
|
||||||
|
'data-method' => 'POST',
|
||||||
|
'data-loader' => 'modal',
|
||||||
|
'data-message' => Yii::t('MarketplaceModule.base', 'Installing module...'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trim($html) === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_replace('{buttons}', $html, $this->template);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\marketplace\widgets;
|
||||||
|
|
||||||
|
use humhub\components\Widget;
|
||||||
|
use humhub\modules\marketplace\models\Module;
|
||||||
|
use humhub\widgets\Button;
|
||||||
|
use Yii;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleInstallActionButtons shows actions for module with available update
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class ModuleUpdateActionButtons extends Widget
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Module
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Template for buttons
|
||||||
|
*/
|
||||||
|
public $template = '<div class="card-footer">{buttons}</div>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
if (!isset($this->module->latestCompatibleVersion) || !$this->module->isInstalled()) {
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= Button::asLink(Yii::t('MarketplaceModule.base', 'Update'), ['/marketplace/update/install', 'moduleId' => $this->module->id])
|
||||||
|
->cssClass('btn btn-xs btn-info active')
|
||||||
|
->options(['data-action-click' => 'marketplace.update']);
|
||||||
|
|
||||||
|
$html .= Button::asLink(Yii::t('MarketplaceModule.base', 'Changelog'), $this->module->marketplaceUrl . '#changelog')
|
||||||
|
->cssClass('btn btn-xs btn-info')
|
||||||
|
->options(['target' => '_blank']);
|
||||||
|
|
||||||
|
return str_replace('{buttons}', $html, $this->template);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
use humhub\libs\Html;
|
||||||
|
use humhub\modules\admin\widgets\ModuleControls;
|
||||||
|
use humhub\modules\admin\widgets\ModuleStatus;
|
||||||
|
use humhub\modules\marketplace\models\Module;
|
||||||
|
use humhub\modules\marketplace\widgets\ModuleInstallActionButtons;
|
||||||
|
use humhub\modules\ui\icon\widgets\Icon;
|
||||||
|
|
||||||
|
/* @var Module $module */
|
||||||
|
?>
|
||||||
|
<div class="card-panel">
|
||||||
|
<?= ModuleStatus::widget(['module' => $module]) ?>
|
||||||
|
<div class="card-header">
|
||||||
|
<?= Html::img($module->image, [
|
||||||
|
'class' => 'media-object img-rounded',
|
||||||
|
'data-src' => 'holder.js/94x94',
|
||||||
|
'alt' => '94x94',
|
||||||
|
'style' => 'width:94px;height:94px',
|
||||||
|
]) ?>
|
||||||
|
<?= ModuleControls::widget(['module' => $module]) ?>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title"><?= $module->name . ($module->featured ? ' ' . Icon::get('star')->color('info') : '') ?></div>
|
||||||
|
<div><?= $module->latestVersion ?></div>
|
||||||
|
<div><?= $module->description ?></div>
|
||||||
|
</div>
|
||||||
|
<?= ModuleInstallActionButtons::widget(['module' => $module]) ?>
|
||||||
|
</div>
|
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
use humhub\libs\Html;
|
||||||
|
use humhub\modules\marketplace\assets\Assets;
|
||||||
|
use humhub\modules\marketplace\models\Module;
|
||||||
|
use humhub\modules\marketplace\widgets\ModuleUpdateActionButtons;
|
||||||
|
use humhub\modules\ui\view\components\View;
|
||||||
|
|
||||||
|
/* @var View $this */
|
||||||
|
/* @var Module $module */
|
||||||
|
|
||||||
|
Assets::register($this);
|
||||||
|
?>
|
||||||
|
<div class="card-panel">
|
||||||
|
<div class="card-header">
|
||||||
|
<?= Html::img($module->image, [
|
||||||
|
'class' => 'media-object img-rounded',
|
||||||
|
'data-src' => 'holder.js/60x60',
|
||||||
|
'alt' => '60x60',
|
||||||
|
'style' => 'width:60px;height:60px',
|
||||||
|
]) ?>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title"><?= $module->name ?></div>
|
||||||
|
<div><?= Yii::$app->moduleManager->getModule($module->id)->getVersion() ?> → <?= $module->latestCompatibleVersion ?></div>
|
||||||
|
</div>
|
||||||
|
<?= ModuleUpdateActionButtons::widget(['module' => $module]) ?>
|
||||||
|
</div>
|
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
use humhub\modules\ui\icon\widgets\Icon;
|
||||||
|
|
||||||
|
/* @var string $class */
|
||||||
|
/* @var string $icon */
|
||||||
|
/* @var string $info */
|
||||||
|
/* @var string $link */
|
||||||
|
?>
|
||||||
|
<div class="row directory-filters-footer <?= $class ?>">
|
||||||
|
<div class="col-md-8 col-xs-12">
|
||||||
|
<?= Icon::get($icon, ['htmlOptions' => ['class' => 'filter-footer-icon']]) ?>
|
||||||
|
<strong><?= $info ?></strong>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 col-xs-12 text-right">
|
||||||
|
<?= $link ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -61,7 +61,7 @@ class SpacesController extends Controller
|
|||||||
$urlParams = Yii::$app->request->getQueryParams();
|
$urlParams = Yii::$app->request->getQueryParams();
|
||||||
unset($urlParams['page']);
|
unset($urlParams['page']);
|
||||||
array_unshift($urlParams, '/space/spaces/load-more');
|
array_unshift($urlParams, '/space/spaces/load-more');
|
||||||
$this->getView()->registerJsConfig('directory', [
|
$this->getView()->registerJsConfig('cards', [
|
||||||
'loadMoreUrl' => Url::to($urlParams),
|
'loadMoreUrl' => Url::to($urlParams),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -25,7 +25,10 @@ class ModuleController extends Controller
|
|||||||
{
|
{
|
||||||
$space = $this->getSpace();
|
$space = $this->getSpace();
|
||||||
|
|
||||||
return $this->render('index', ['availableModules' => $space->getAvailableModules(), 'space' => $space]);
|
return $this->render('index', [
|
||||||
|
'space' => $space,
|
||||||
|
'modules' => $space->getAvailableModules(),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,61 +1,35 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use yii\helpers\Html;
|
use humhub\modules\admin\assets\ModuleAsset;
|
||||||
|
use humhub\modules\content\components\ContentContainerModule;
|
||||||
|
use humhub\modules\content\widgets\ModuleCard;
|
||||||
|
use humhub\modules\space\models\Space;
|
||||||
|
use humhub\modules\ui\view\helpers\ThemeHelper;
|
||||||
|
|
||||||
|
/* @var Space $space */
|
||||||
|
/* @var ContentContainerModule[] $modules */
|
||||||
|
|
||||||
|
ModuleAsset::register($this);
|
||||||
?>
|
?>
|
||||||
|
<div class="<?php if (ThemeHelper::isFluid()) : ?>container-fluid<?php else: ?>container<?php endif; ?> container-cards container-modules container-content-modules">
|
||||||
|
<h4><?= Yii::t('SpaceModule.manage', '<strong>Space</strong> Modules'); ?></h4>
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="row cards">
|
||||||
<div class="panel-heading">
|
<?php if (empty($modules)) : ?>
|
||||||
<?= Yii::t('SpaceModule.manage', '<strong>Space</strong> Modules'); ?>
|
<div class="col-md-12">
|
||||||
</div>
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
<?= Yii::t('SpaceModule.manage', 'Currently there are no modules available for this space!'); ?>
|
||||||
<?php if (count($availableModules) == 0) : ?>
|
</div>
|
||||||
<p><?= Yii::t('SpaceModule.manage', 'Currently there are no modules available for this space!'); ?></p>
|
|
||||||
<?php else : ?>
|
|
||||||
<?= Yii::t('SpaceModule.manage', 'Enhance this space with modules.'); ?><br>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
|
|
||||||
<?php foreach ($availableModules as $moduleId => $module): ?>
|
|
||||||
<hr>
|
|
||||||
<div class="media">
|
|
||||||
<img class="media-object img-rounded pull-left" data-src="holder.js/64x64" alt="64x64"
|
|
||||||
style="width: 64px; height: 64px;"
|
|
||||||
src="<?= $module->getContentContainerImage($space); ?>">
|
|
||||||
|
|
||||||
<div class="media-body">
|
|
||||||
<h4 class="media-heading"><?= $module->getContentContainerName($space); ?>
|
|
||||||
<?php if ($space->isModuleEnabled($moduleId)) : ?>
|
|
||||||
<small><span class="label label-success"><?= Yii::t('SpaceModule.manage', 'Activated'); ?></span></small>
|
|
||||||
<?php endif; ?>
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<p><?= $module->getContentContainerDescription($space); ?></p>
|
|
||||||
|
|
||||||
<?php if ($space->canDisableModule($moduleId)) : ?>
|
|
||||||
<a href="#" style="<?= $space->isModuleEnabled($moduleId) ? '' : 'display:none' ?>"
|
|
||||||
data-action-click="content.container.disableModule"
|
|
||||||
data-action-url="<?= $space->createUrl('/space/manage/module/disable', ['moduleId' => $moduleId]) ?>" data-reload="1"
|
|
||||||
data-action-confirm="<?= Yii::t('SpaceModule.manage', 'Are you sure? *ALL* module data for this space will be deleted!') ?>"
|
|
||||||
class="btn btn-sm btn-primary disable disable-module-<?= $moduleId ?>" data-ui-loader>
|
|
||||||
<?= Yii::t('SpaceModule.manage', 'Disable') ?>
|
|
||||||
</a>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if ($module->getContentContainerConfigUrl($space) && $space->isModuleEnabled($moduleId)) : ?>
|
|
||||||
<a href="<?= $module->getContentContainerConfigUrl($space) ?>" class="btn btn-sm btn-default configure-module-<?= $moduleId ?>">
|
|
||||||
<?= Yii::t('SpaceModule.manage', 'Configure') ?>
|
|
||||||
</a>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<a href="#" style="<?= $space->isModuleEnabled($moduleId) ? 'display:none' : '' ?>"
|
|
||||||
data-action-click="content.container.enableModule" data-action-url="<?= $space->createUrl('/space/manage/module/enable', ['moduleId' => $moduleId]) ?>" data-reload="1"
|
|
||||||
class="btn btn-sm btn-primary enable enable-module-<?= $moduleId ?>" data-ui-loader>
|
|
||||||
<?= Yii::t('SpaceModule.manage', 'Enable') ?>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php foreach ($modules as $module) : ?>
|
||||||
|
<?= ModuleCard::widget([
|
||||||
|
'contentContainer' => $space,
|
||||||
|
'module' => $module,
|
||||||
|
]); ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
31
protected/humhub/modules/space/views/create/moduleCard.php
Normal file
31
protected/humhub/modules/space/views/create/moduleCard.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\libs\Helpers;
|
||||||
|
use humhub\libs\Html;
|
||||||
|
use humhub\modules\space\models\Space;
|
||||||
|
use humhub\modules\space\widgets\ModuleActionButtons;
|
||||||
|
|
||||||
|
/* @var $module Module */
|
||||||
|
/* @var $contentContainer Space */
|
||||||
|
?>
|
||||||
|
<div class="card-panel">
|
||||||
|
<div class="card-header">
|
||||||
|
<?= Html::img($module->getImage(), [
|
||||||
|
'class' => 'media-object img-rounded',
|
||||||
|
'data-src' => 'holder.js/94x94',
|
||||||
|
'alt' => '94x94',
|
||||||
|
'style' => 'width:94px;height:94px',
|
||||||
|
]) ?>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title"><?= $module->getName() ?></div>
|
||||||
|
<div><?= Helpers::truncateText($module->getContentContainerDescription($contentContainer), 75); ?></div>
|
||||||
|
</div>
|
||||||
|
<?= ModuleActionButtons::widget(['module' => $module, 'space' => $contentContainer]) ?>
|
||||||
|
</div>
|
@ -1,15 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use humhub\modules\admin\assets\ModuleAsset;
|
||||||
|
use humhub\modules\content\widgets\ModuleCard;
|
||||||
use humhub\modules\space\assets\SpaceAsset;
|
use humhub\modules\space\assets\SpaceAsset;
|
||||||
use humhub\libs\Helpers;
|
use humhub\modules\space\models\Space;
|
||||||
|
use humhub\modules\ui\view\components\View;
|
||||||
use yii\helpers\Url;
|
use yii\helpers\Url;
|
||||||
|
|
||||||
/* @var $availableModules array available modules for space*/
|
/* @var $availableModules array available modules for space */
|
||||||
|
/* @var $space Space */
|
||||||
|
/* @var $this View */
|
||||||
|
|
||||||
SpaceAsset::register($this);
|
SpaceAsset::register($this);
|
||||||
|
ModuleAsset::register($this);
|
||||||
?>
|
?>
|
||||||
<div class="modal-dialog modal-dialog-medium animated fadeIn">
|
<div class="modal-dialog modal-dialog-medium animated fadeIn" style="width:100%;max-width:900px">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 class="modal-title" id="myModalLabel">
|
<h4 class="modal-title" id="myModalLabel">
|
||||||
@ -17,48 +22,21 @@ SpaceAsset::register($this);
|
|||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<br><br>
|
<div class="container container-cards container-modules container-create-space-modules">
|
||||||
|
<div class="row cards">
|
||||||
<div class="row">
|
<?php foreach ($availableModules as $moduleId => $module) : ?>
|
||||||
|
<?= ModuleCard::widget([
|
||||||
<?php foreach ($availableModules as $moduleId => $module) :?>
|
'contentContainer' => $space,
|
||||||
<div class="col-md-6">
|
'module' => $module,
|
||||||
<div class="media well well-small ">
|
'view' => '@humhub/modules/space/views/create/moduleCard'
|
||||||
<img class="media-object img-rounded pull-left" data-src="holder.js/64x64" alt="64x64"
|
]); ?>
|
||||||
style="width: 64px; height: 64px;"
|
<?php endforeach; ?>
|
||||||
src="<?= $module->getContentContainerImage($space); ?>">
|
</div>
|
||||||
|
|
||||||
<div class="media-body">
|
|
||||||
<h4 class="media-heading"><?= $module->getContentContainerName($space); ?></h4>
|
|
||||||
|
|
||||||
<p style="height: 35px;"><?= Helpers::truncateText($module->getContentContainerDescription($space), 75); ?></p>
|
|
||||||
|
|
||||||
<a href="#" class="btn btn-sm btn-primary enable"
|
|
||||||
data-action-click="content.container.enableModule"
|
|
||||||
data-ui-loader
|
|
||||||
<?php if ($space->isModuleEnabled($moduleId)): ?>style="display:none"<?php endif; ?>
|
|
||||||
data-action-url="<?= $space->createUrl('/space/manage/module/enable', ['moduleId' => $moduleId]); ?>">
|
|
||||||
<?= Yii::t('SpaceModule.manage', 'Enable'); ?>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="#" class="btn btn-sm btn-primary disable"
|
|
||||||
<?php if (!$space->isModuleEnabled($moduleId)): ?>style="display:none"<?php endif; ?>
|
|
||||||
data-action-click="content.container.disableModule"
|
|
||||||
data-ui-loader
|
|
||||||
data-action-url="<?= $space->createUrl('/space/manage/module/disable', ['moduleId' => $moduleId]); ?>">
|
|
||||||
<?= Yii::t('SpaceModule.manage', 'Disable'); ?>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
</div>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<a href="#" class="btn btn-primary"
|
<a href="#" class="btn btn-info"
|
||||||
data-action-click="ui.modal.post"
|
data-action-click="ui.modal.post"
|
||||||
data-ui-loader
|
data-ui-loader
|
||||||
data-action-url="<?= Url::to(['/space/create/invite', 'spaceId' => $space->id]); ?>">
|
data-action-url="<?= Url::to(['/space/create/invite', 'spaceId' => $space->id]); ?>">
|
||||||
|
@ -4,6 +4,6 @@ use humhub\modules\ui\view\helpers\ThemeHelper;
|
|||||||
|
|
||||||
/* @var $content string */
|
/* @var $content string */
|
||||||
?>
|
?>
|
||||||
<div class="<?php if (ThemeHelper::isFluid()): ?>container-fluid<?php else: ?>container<?php endif; ?> container-directory container-spaces">
|
<div class="<?php if (ThemeHelper::isFluid()): ?>container-fluid<?php else: ?>container<?php endif; ?> container-cards container-spaces">
|
||||||
<?= $content; ?>
|
<?= $content; ?>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* @license https://www.humhub.com/licences
|
* @license https://www.humhub.com/licences
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use humhub\assets\DirectoryAsset;
|
use humhub\assets\CardsAsset;
|
||||||
use humhub\libs\Html;
|
use humhub\libs\Html;
|
||||||
use humhub\modules\space\components\SpaceDirectoryQuery;
|
use humhub\modules\space\components\SpaceDirectoryQuery;
|
||||||
use humhub\modules\space\widgets\SpaceDirectoryCard;
|
use humhub\modules\space\widgets\SpaceDirectoryCard;
|
||||||
@ -15,7 +15,7 @@ use yii\web\View;
|
|||||||
/* @var $this View */
|
/* @var $this View */
|
||||||
/* @var $spaces SpaceDirectoryQuery */
|
/* @var $spaces SpaceDirectoryQuery */
|
||||||
|
|
||||||
DirectoryAsset::register($this);
|
CardsAsset::register($this);
|
||||||
?>
|
?>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ DirectoryAsset::register($this);
|
|||||||
|
|
||||||
<?php if (!$spaces->isLastPage()) : ?>
|
<?php if (!$spaces->isLastPage()) : ?>
|
||||||
<?= Html::tag('div', '', [
|
<?= Html::tag('div', '', [
|
||||||
'class' => 'directory-end',
|
'class' => 'cards-end',
|
||||||
'data-current-page' => $spaces->pagination->getPage() + 1,
|
'data-current-page' => $spaces->pagination->getPage() + 1,
|
||||||
'data-total-pages' => $spaces->pagination->getPageCount(),
|
'data-total-pages' => $spaces->pagination->getPageCount(),
|
||||||
]) ?>
|
]) ?>
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace humhub\modules\space\widgets;
|
||||||
|
|
||||||
|
use humhub\components\Module;
|
||||||
|
use humhub\components\Widget;
|
||||||
|
use humhub\modules\space\models\Space;
|
||||||
|
use humhub\widgets\Button;
|
||||||
|
use Yii;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleActionsButton shows actions for module of Space on creating it
|
||||||
|
*
|
||||||
|
* @since 1.11
|
||||||
|
* @author Luke
|
||||||
|
*/
|
||||||
|
class ModuleActionButtons extends Widget
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Module
|
||||||
|
*/
|
||||||
|
public $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Space
|
||||||
|
*/
|
||||||
|
public $space;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Template for buttons
|
||||||
|
*/
|
||||||
|
public $template = '<div class="card-footer">{buttons}</div>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
$html .= Button::asLink(Yii::t('SpaceModule.manage', 'Activate'), '#')
|
||||||
|
->cssClass('btn btn-sm btn-info enable')
|
||||||
|
->style($this->space->isModuleEnabled($this->module->id) ? 'display:none' : '')
|
||||||
|
->loader()
|
||||||
|
->options([
|
||||||
|
'data-action-click' => 'content.container.enableModule',
|
||||||
|
'data-action-url' => $this->space->createUrl('/space/manage/module/enable', ['moduleId' => $this->module->id]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$html .= Button::asLink('<span class="glyphicon glyphicon-ok"></span> ' . Yii::t('ContentModule.modules', 'Activated'), '#')
|
||||||
|
->cssClass('btn btn-sm btn-info active disable')
|
||||||
|
->style(!$this->space->isModuleEnabled($this->module->id) ? 'display:none' : '')
|
||||||
|
->loader()
|
||||||
|
->options([
|
||||||
|
'data-action-click' => 'content.container.disableModule',
|
||||||
|
'data-action-url' => $this->space->createUrl('/space/manage/module/disable', ['moduleId' => $this->module->id]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (trim($html) === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_replace('{buttons}', $html, $this->template);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,7 @@ use yii\helpers\Url;
|
|||||||
/* @var $this \humhub\modules\ui\view\components\View */
|
/* @var $this \humhub\modules\ui\view\components\View */
|
||||||
|
|
||||||
$isAmind = Yii::$app->user->isAdmin();
|
$isAmind = Yii::$app->user->isAdmin();
|
||||||
$nextUrl = $isAmind ? Url::to(['/marketplace/browse', 'tour' => 'true']) : '';
|
$nextUrl = $isAmind ? Url::to(['/admin/module/list', 'tour' => 'true']) : '';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<script <?= \humhub\libs\Html::nonce() ?>>
|
<script <?= \humhub\libs\Html::nonce() ?>>
|
||||||
|
@ -48,7 +48,7 @@ use yii\helpers\Url;
|
|||||||
</li>
|
</li>
|
||||||
<?php if (Yii::$app->user->isAdmin() == true) : ?>
|
<?php if (Yii::$app->user->isAdmin() == true) : ?>
|
||||||
<li class="<?php if ($administration == 1) : ?>completed<?php endif; ?>">
|
<li class="<?php if ($administration == 1) : ?>completed<?php endif; ?>">
|
||||||
<a href="<?php echo Url::to(['/marketplace/browse', 'tour' => 'true']); ?>" data-pjax-prevent>
|
<a href="<?php echo Url::to(['/admin/module/list', 'tour' => 'true']); ?>" data-pjax-prevent>
|
||||||
<i class="fa fa-play-circle-o"></i><?php echo Yii::t('TourModule.base', '<strong>Guide:</strong> Administration (Modules)'); ?>
|
<i class="fa fa-play-circle-o"></i><?php echo Yii::t('TourModule.base', '<strong>Guide:</strong> Administration (Modules)'); ?>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -9,11 +9,12 @@ namespace humhub\modules\ui\widgets;
|
|||||||
|
|
||||||
use humhub\components\Widget;
|
use humhub\components\Widget;
|
||||||
use humhub\libs\Html;
|
use humhub\libs\Html;
|
||||||
|
use humhub\widgets\Button;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\helpers\ArrayHelper;
|
use yii\helpers\ArrayHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DirectoryFilters displays the filters on the directory people/spaces pages
|
* DirectoryFilters displays the filters on the directory people/spaces/modules pages
|
||||||
*
|
*
|
||||||
* @since 1.9
|
* @since 1.9
|
||||||
* @author Luke
|
* @author Luke
|
||||||
@ -30,6 +31,11 @@ abstract class DirectoryFilters extends Widget
|
|||||||
*/
|
*/
|
||||||
public $pageUrl;
|
public $pageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool True - if paganation is used for the filtered results
|
||||||
|
* @since 1.11
|
||||||
|
*/
|
||||||
|
public $paginationUsed = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
@ -38,6 +44,13 @@ abstract class DirectoryFilters extends Widget
|
|||||||
{
|
{
|
||||||
$this->initDefaultFilters();
|
$this->initDefaultFilters();
|
||||||
|
|
||||||
|
$this->addFilter('reset', [
|
||||||
|
'type' => 'info',
|
||||||
|
'wrapperClass' => 'col-md-2 form-search-without-info',
|
||||||
|
'info' => Html::a(Yii::t('UiModule.base', 'Reset filters'), [$this->pageUrl], ['class' => 'form-search-reset']),
|
||||||
|
'sortOrder' => 10000,
|
||||||
|
]);
|
||||||
|
|
||||||
parent::init();
|
parent::init();
|
||||||
|
|
||||||
ArrayHelper::multisort($this->filters, 'sortOrder');
|
ArrayHelper::multisort($this->filters, 'sortOrder');
|
||||||
@ -88,11 +101,40 @@ abstract class DirectoryFilters extends Widget
|
|||||||
switch ($data['type']) {
|
switch ($data['type']) {
|
||||||
case 'dropdown':
|
case 'dropdown':
|
||||||
case 'dropdownlist':
|
case 'dropdownlist':
|
||||||
$inputOptions['data-action-change'] = 'directory.applyFilters';
|
$inputOptions['data-action-change'] = 'cards.applyFilters';
|
||||||
$inputOptions['options'] = ['separator' => ['disabled' => '']];
|
$inputOptions['options'] = ['separator' => ['disabled' => '']];
|
||||||
$inputHtml = Html::dropDownList($filter, self::getValue($filter), $data['options'], $inputOptions);
|
$inputHtml = Html::dropDownList($filter, self::getValue($filter), $data['options'], $inputOptions);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'tags':
|
||||||
|
$inputHtml = '';
|
||||||
|
if (empty($data['tags'])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$activeTags = self::getValue($filter);
|
||||||
|
$filterOptions = empty($data['multiple']) ? [] : ['data-multiple' => 1];
|
||||||
|
$inputHtml .= Html::hiddenInput($filter, $activeTags, $filterOptions);
|
||||||
|
$activeTags = empty($activeTags) ? [] : explode(',', $activeTags);
|
||||||
|
|
||||||
|
foreach ($data['tags'] as $tagKey => $tagLabel) {
|
||||||
|
$isActiveTag = (empty($tagKey) && empty($activeTags))
|
||||||
|
|| in_array($tagKey, $activeTags);
|
||||||
|
|
||||||
|
$inputHtml .= Button::none($tagLabel)
|
||||||
|
->options(['class' => 'btn btn-sm btn-info' . ($isActiveTag ? ' active' : '')])
|
||||||
|
->action('cards.selectTag')
|
||||||
|
->options([
|
||||||
|
'data-filter' => $filter,
|
||||||
|
'data-tag' => $tagKey,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'info':
|
||||||
|
$inputHtml = $data['info'];
|
||||||
|
break;
|
||||||
|
|
||||||
case 'input':
|
case 'input':
|
||||||
case 'text':
|
case 'text':
|
||||||
default:
|
default:
|
||||||
|
@ -13,6 +13,8 @@ use humhub\modules\ui\widgets\DirectoryFilters;
|
|||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="<?= $data['wrapperClass'] ?>">
|
<div class="<?= $data['wrapperClass'] ?>">
|
||||||
<div class="<?= $data['titleClass'] ?>"><?= $data['title'] ?></div>
|
<?php if(isset($data['title'])) : ?>
|
||||||
|
<div class="<?= $data['titleClass'] ?>"><?= $data['title'] ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
<?= $directoryFilters->renderFilterInput($filter, $data) ?>
|
<?= $directoryFilters->renderFilterInput($filter, $data) ?>
|
||||||
</div>
|
</div>
|
@ -13,11 +13,10 @@ use yii\helpers\Url;
|
|||||||
?>
|
?>
|
||||||
|
|
||||||
<?= Html::beginForm(Url::to([$directoryFilters->pageUrl]), 'get', ['class' => 'form-search']); ?>
|
<?= Html::beginForm(Url::to([$directoryFilters->pageUrl]), 'get', ['class' => 'form-search']); ?>
|
||||||
<?= Html::hiddenInput('page', '1'); ?>
|
<?php if ($directoryFilters->paginationUsed) : ?>
|
||||||
|
<?= Html::hiddenInput('page', '1'); ?>
|
||||||
|
<?php endif; ?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<?= $directoryFilters->renderFilters() ?>
|
<?= $directoryFilters->renderFilters() ?>
|
||||||
<div class="col-md-2 form-search-without-info">
|
|
||||||
<?= Html::a(Yii::t('UiModule.base', 'Reset filters'), Url::to([$directoryFilters->pageUrl]), ['class' => 'form-search-reset']); ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<?= Html::endForm(); ?>
|
<?= Html::endForm(); ?>
|
@ -248,10 +248,15 @@ class AccountController extends BaseAccountController
|
|||||||
*/
|
*/
|
||||||
public function actionEditModules()
|
public function actionEditModules()
|
||||||
{
|
{
|
||||||
$user = Yii::$app->user->getIdentity();
|
$this->subLayout = '@humhub/modules/user/views/account/_userModulesLayout';
|
||||||
$availableModules = $user->getAvailableModules();
|
|
||||||
|
|
||||||
return $this->render('editModules', ['user' => $user, 'availableModules' => $availableModules]);
|
/* @var User $user */
|
||||||
|
$user = Yii::$app->user->getIdentity();
|
||||||
|
|
||||||
|
return $this->render('editModules', [
|
||||||
|
'user' => $user,
|
||||||
|
'modules' => $user->getAvailableModules(),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,7 +60,7 @@ class PeopleController extends Controller
|
|||||||
$urlParams = Yii::$app->request->getQueryParams();
|
$urlParams = Yii::$app->request->getQueryParams();
|
||||||
unset($urlParams['page']);
|
unset($urlParams['page']);
|
||||||
array_unshift($urlParams, '/user/people/load-more');
|
array_unshift($urlParams, '/user/people/load-more');
|
||||||
$this->getView()->registerJsConfig('directory', [
|
$this->getView()->registerJsConfig('cards', [
|
||||||
'loadMoreUrl' => Url::to($urlParams),
|
'loadMoreUrl' => Url::to($urlParams),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.humhub.org/
|
||||||
|
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||||
|
* @license https://www.humhub.com/licences
|
||||||
|
*/
|
||||||
|
|
||||||
|
use humhub\modules\user\widgets\AccountMenu;
|
||||||
|
use humhub\widgets\FooterMenu;
|
||||||
|
|
||||||
|
/* @var string $content */
|
||||||
|
?>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<?= AccountMenu::widget() ?>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<?= $content ?>
|
||||||
|
<?= FooterMenu::widget(['location' => FooterMenu::LOCATION_FULL_PAGE]); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,48 +1,35 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use yii\helpers\Html;
|
use humhub\modules\admin\assets\ModuleAsset;
|
||||||
use yii\helpers\Url;
|
use humhub\modules\content\components\ContentContainerModule;
|
||||||
|
use humhub\modules\content\widgets\ModuleCard;
|
||||||
|
use humhub\modules\user\models\User;
|
||||||
|
use humhub\modules\ui\view\helpers\ThemeHelper;
|
||||||
|
|
||||||
|
/* @var User $user */
|
||||||
|
/* @var ContentContainerModule[] $modules */
|
||||||
|
|
||||||
|
ModuleAsset::register($this);
|
||||||
?>
|
?>
|
||||||
<div class="panel-heading">
|
<div class="container container-cards container-modules container-content-modules">
|
||||||
<?php echo Yii::t('UserModule.account', '<strong>User</strong> modules'); ?>
|
<h4><?= Yii::t('UserModule.manage', '<strong>User</strong> modules'); ?></h4>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="help-block"><?php echo Yii::t('UserModule.account', 'Enhance your profile with modules.'); ?></div>
|
|
||||||
|
|
||||||
<?php foreach ($availableModules as $moduleId => $module): ?>
|
|
||||||
<hr>
|
|
||||||
<div class="media">
|
|
||||||
<a class="pull-left" href="#">
|
|
||||||
<img src="<?= $module->getContentContainerImage($user); ?>"
|
|
||||||
class="" width="64" height="64">
|
|
||||||
</a>
|
|
||||||
<div class="media-body">
|
|
||||||
<h4 class="media-heading"><?php echo $module->getContentContainerName($user); ?></h4>
|
|
||||||
<p><?= $module->getContentContainerDescription($user); ?></p>
|
|
||||||
|
|
||||||
|
|
||||||
<?php if ($user->canDisableModule($module->id)): ?>
|
|
||||||
<a href="#" style="<?= $user->isModuleEnabled($module->id) ? '' : 'display:none' ?>"
|
|
||||||
data-action-click="content.container.disableModule"
|
|
||||||
data-action-url="<?= Url::to(['/user/account/disable-module', 'moduleId' => $module->id]) ?>" data-reload="1"
|
|
||||||
data-action-confirm="<?= Yii::t('UserModule.account', 'Are you really sure? *ALL* module data for your profile will be deleted!') ?>"
|
|
||||||
class="btn btn-sm btn-primary disable disable-module-<?= $module->id ?>" data-ui-loader>
|
|
||||||
<?= Yii::t('UserModule.account', 'Disable') ?>
|
|
||||||
</a>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if ($module->getContentContainerConfigUrl($user) && $user->isModuleEnabled($module->id)) : ?>
|
|
||||||
<?= Html::a(Yii::t('UserModule.account', 'Configure'), $module->getContentContainerConfigUrl($user), ['class' => 'btn btn-sm btn-default']); ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<a href="#" style="<?= $user->isModuleEnabled($module->id) ? 'display:none' : '' ?>"
|
|
||||||
data-action-click="content.container.enableModule" data-action-url="<?= Url::to(['/user/account/enable-module', 'moduleId' => $module->id]) ?>" data-reload="1"
|
|
||||||
class="btn btn-sm btn-primary enable enable-module-<?= $module->id ?>" data-ui-loader>
|
|
||||||
<?= Yii::t('UserModule.account', 'Enable') ?>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
|
<div class="row cards">
|
||||||
|
<?php if (empty($modules)) : ?>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<?= Yii::t('UserModule.manage', 'Currently there are no modules available for you!'); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<?php endif; ?>
|
||||||
<?php endforeach; ?>
|
|
||||||
|
<?php foreach ($modules as $module) : ?>
|
||||||
|
<?= ModuleCard::widget([
|
||||||
|
'contentContainer' => $user,
|
||||||
|
'module' => $module,
|
||||||
|
]); ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
@ -4,6 +4,6 @@ use humhub\modules\ui\view\helpers\ThemeHelper;
|
|||||||
|
|
||||||
/* @var $content string */
|
/* @var $content string */
|
||||||
?>
|
?>
|
||||||
<div class="<?php if (ThemeHelper::isFluid()): ?>container-fluid<?php else: ?>container<?php endif; ?> container-directory container-people">
|
<div class="<?php if (ThemeHelper::isFluid()): ?>container-fluid<?php else: ?>container<?php endif; ?> container-cards container-people">
|
||||||
<?= $content; ?>
|
<?= $content; ?>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use humhub\assets\DirectoryAsset;
|
use humhub\assets\CardsAsset;
|
||||||
use humhub\libs\Html;
|
use humhub\libs\Html;
|
||||||
use humhub\modules\user\components\PeopleQuery;
|
use humhub\modules\user\components\PeopleQuery;
|
||||||
use humhub\modules\user\widgets\PeopleCard;
|
use humhub\modules\user\widgets\PeopleCard;
|
||||||
@ -11,7 +11,7 @@ use humhub\widgets\ModalButton;
|
|||||||
/* @var $people PeopleQuery */
|
/* @var $people PeopleQuery */
|
||||||
/* @var $showInviteButton bool */
|
/* @var $showInviteButton bool */
|
||||||
|
|
||||||
DirectoryAsset::register($this);
|
CardsAsset::register($this);
|
||||||
?>
|
?>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ DirectoryAsset::register($this);
|
|||||||
|
|
||||||
<?php if (!$people->isLastPage()) : ?>
|
<?php if (!$people->isLastPage()) : ?>
|
||||||
<?= Html::tag('div', '', [
|
<?= Html::tag('div', '', [
|
||||||
'class' => 'directory-end',
|
'class' => 'cards-end',
|
||||||
'data-current-page' => $people->pagination->getPage() + 1,
|
'data-current-page' => $people->pagination->getPage() + 1,
|
||||||
'data-total-pages' => $people->pagination->getPageCount(),
|
'data-total-pages' => $people->pagination->getPageCount(),
|
||||||
'data-ui-loader' => '',
|
'data-ui-loader' => '',
|
||||||
|
@ -86,7 +86,7 @@ class PeopleFilters extends DirectoryFilters
|
|||||||
$profileFieldSortOrder = 1000;
|
$profileFieldSortOrder = 1000;
|
||||||
foreach ($profileFields as $profileField) {
|
foreach ($profileFields as $profileField) {
|
||||||
$this->initProfileFieldFilter($profileField, $profileFieldSortOrder);
|
$this->initProfileFieldFilter($profileField, $profileFieldSortOrder);
|
||||||
$profileFieldSortOrder += 100;
|
$profileFieldSortOrder += 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
124
static/js/humhub/humhub.cards.js
Normal file
124
static/js/humhub/humhub.cards.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
humhub.module('cards', function(module, require, $) {
|
||||||
|
const client = require('client');
|
||||||
|
const loader = require('ui.loader');
|
||||||
|
|
||||||
|
const applyFilters = function(evt) {
|
||||||
|
$(evt.$trigger).closest('form').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectTag = function (evt) {
|
||||||
|
const filter = $(evt.$trigger).data('filter');
|
||||||
|
const tag = $(evt.$trigger).data('tag');
|
||||||
|
const isMultiple = $(evt.$trigger).data('multiple');
|
||||||
|
const input = $(evt.$trigger).closest('form').find('input[type=hidden][name=' + filter + ']');
|
||||||
|
|
||||||
|
if (tag === '') {
|
||||||
|
input.val('');
|
||||||
|
applyFilters(evt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentTags = input.val();
|
||||||
|
currentTags = currentTags === '' ? [] : currentTags.split(',');
|
||||||
|
let newTags = [];
|
||||||
|
let tagIsActive = false;
|
||||||
|
for (let i = 0; i < currentTags.length; i++) {
|
||||||
|
if (currentTags[i] === tag) {
|
||||||
|
tagIsActive = true;
|
||||||
|
} else if (isMultiple) {
|
||||||
|
newTags.push(currentTags[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!tagIsActive) {
|
||||||
|
newTags.push(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.val(newTags.join(','));
|
||||||
|
applyFilters(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadMore = function(cardsEndIndicator) {
|
||||||
|
const urlParams = {page: cardsEndIndicator.data('current-page') + 1};
|
||||||
|
|
||||||
|
$('.cards-end').data('isLoading', true);
|
||||||
|
loader.append(cardsEndIndicator);
|
||||||
|
client.get(module.config.loadMoreUrl, {data: urlParams}).then(function (response) {
|
||||||
|
$('.container-cards .card:hidden').show();
|
||||||
|
$('.container-cards .cards').append(response.response);
|
||||||
|
if (urlParams.page == cardsEndIndicator.data('total-pages')) {
|
||||||
|
// Remove the directory end indicator because the last page was loaded
|
||||||
|
cardsEndIndicator.remove();
|
||||||
|
} else {
|
||||||
|
cardsEndIndicator.data('current-page', urlParams.page);
|
||||||
|
hideLastNotCompletedRow();
|
||||||
|
}
|
||||||
|
}).catch(function(err) {
|
||||||
|
module.log.error(err, true);
|
||||||
|
reject();
|
||||||
|
}).finally(function() {
|
||||||
|
loader.reset(cardsEndIndicator);
|
||||||
|
$('.cards-end').data('isLoading', false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hideLastNotCompletedRow = function() {
|
||||||
|
const cardsNum = $('.container-cards .card').length;
|
||||||
|
if (!cardsNum) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cardsEndIndicator = $('.cards-end');
|
||||||
|
if (cardsEndIndicator.data('current-page') === cardsEndIndicator.data('total-pages')) {
|
||||||
|
// No reason to hide a not completed row if current page is last
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cardsPerRow = Math.floor($('.container-cards .row').outerWidth() / $('.container-cards .card:first').width());
|
||||||
|
const hideLastCardsNum = cardsNum % cardsPerRow;
|
||||||
|
if (hideLastCardsNum > 0 && cardsNum > cardsPerRow) {
|
||||||
|
// Hide cards from not completed row
|
||||||
|
$('.container-cards .card').slice(-hideLastCardsNum).hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const preventScrollLoading = function () {
|
||||||
|
return $('.cards-end').data('isLoading');
|
||||||
|
};
|
||||||
|
|
||||||
|
const initScroll = function () {
|
||||||
|
if (!window.IntersectionObserver) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const $cardsEndIndicator = $('.cards-end');
|
||||||
|
if (!$cardsEndIndicator.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const observer = new IntersectionObserver(function (entries) {
|
||||||
|
if (preventScrollLoading()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.length && entries[0].isIntersecting) {
|
||||||
|
loadMore($cardsEndIndicator);
|
||||||
|
}
|
||||||
|
}, {rootMargin: '1px'});
|
||||||
|
|
||||||
|
observer.observe($cardsEndIndicator[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = function() {
|
||||||
|
hideLastNotCompletedRow();
|
||||||
|
$('input.form-search-filter[name=keyword]').focus();
|
||||||
|
initScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.export({
|
||||||
|
initOnPjaxLoad: true,
|
||||||
|
init,
|
||||||
|
applyFilters,
|
||||||
|
selectTag,
|
||||||
|
});
|
||||||
|
});
|
@ -1,92 +0,0 @@
|
|||||||
humhub.module('directory', function(module, require, $) {
|
|
||||||
const client = require('client');
|
|
||||||
const loader = require('ui.loader');
|
|
||||||
|
|
||||||
const applyFilters = function(evt) {
|
|
||||||
$(evt.$trigger).closest('form').submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadMore = function(directoryEndIndicator) {
|
|
||||||
const urlParams = {page: directoryEndIndicator.data('current-page') + 1};
|
|
||||||
|
|
||||||
$('.directory-end').data('isLoading', true);
|
|
||||||
loader.append(directoryEndIndicator);
|
|
||||||
client.get(module.config.loadMoreUrl, {data: urlParams}).then(function (response) {
|
|
||||||
$('.container-directory .card:hidden').show();
|
|
||||||
$('.container-directory .cards').append(response.response);
|
|
||||||
if (urlParams.page == directoryEndIndicator.data('total-pages')) {
|
|
||||||
// Remove the directory end indicator because the last page was loaded
|
|
||||||
directoryEndIndicator.remove();
|
|
||||||
} else {
|
|
||||||
directoryEndIndicator.data('current-page', urlParams.page);
|
|
||||||
hideLastNotCompletedRow();
|
|
||||||
}
|
|
||||||
}).catch(function(err) {
|
|
||||||
module.log.error(err, true);
|
|
||||||
reject();
|
|
||||||
}).finally(function() {
|
|
||||||
loader.reset(directoryEndIndicator);
|
|
||||||
$('.directory-end').data('isLoading', false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const hideLastNotCompletedRow = function() {
|
|
||||||
const cardsNum = $('.container-directory .card').length;
|
|
||||||
if (!cardsNum) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const directoryEndIndicator = $('.directory-end');
|
|
||||||
if (directoryEndIndicator.data('current-page') === directoryEndIndicator.data('total-pages')) {
|
|
||||||
// No reason to hide a not completed row if current page is last
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cardsPerRow = Math.floor($('.container-directory .row').outerWidth() / $('.container-directory .card:first').width());
|
|
||||||
const hideLastCardsNum = cardsNum % cardsPerRow;
|
|
||||||
if (hideLastCardsNum > 0 && cardsNum > cardsPerRow) {
|
|
||||||
// Hide cards from not completed row
|
|
||||||
$('.container-directory .card').slice(-hideLastCardsNum).hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const preventScrollLoading = function () {
|
|
||||||
return $('.directory-end').data('isLoading');
|
|
||||||
};
|
|
||||||
|
|
||||||
const initScroll = function () {
|
|
||||||
if (!window.IntersectionObserver) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $directoryEndIndicator = $('.directory-end');
|
|
||||||
if (!$directoryEndIndicator.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const observer = new IntersectionObserver(function (entries) {
|
|
||||||
if (preventScrollLoading()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entries.length && entries[0].isIntersecting) {
|
|
||||||
loadMore($directoryEndIndicator);
|
|
||||||
}
|
|
||||||
}, {rootMargin: '1px'});
|
|
||||||
|
|
||||||
observer.observe($directoryEndIndicator[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const init = function() {
|
|
||||||
hideLastNotCompletedRow();
|
|
||||||
$('input.form-search-filter[name=keyword]').focus();
|
|
||||||
initScroll();
|
|
||||||
}
|
|
||||||
|
|
||||||
module.export({
|
|
||||||
initOnPjaxLoad: true,
|
|
||||||
init,
|
|
||||||
applyFilters,
|
|
||||||
});
|
|
||||||
});
|
|
@ -93,6 +93,9 @@
|
|||||||
&.btn-sm {
|
&.btn-sm {
|
||||||
padding: 3px 7px;
|
padding: 3px 7px;
|
||||||
}
|
}
|
||||||
|
&.btn-xs {
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active:hover,
|
&.active:hover,
|
||||||
@ -138,6 +141,9 @@
|
|||||||
&.btn-sm {
|
&.btn-sm {
|
||||||
padding: 3px 7px;
|
padding: 3px 7px;
|
||||||
}
|
}
|
||||||
|
&.btn-xs {
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active:hover,
|
&.active:hover,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.container-directory {
|
.container-cards {
|
||||||
&.container-fluid {
|
&.container-fluid {
|
||||||
@media (min-width: 500px) {
|
@media (min-width: 500px) {
|
||||||
.card {
|
.card {
|
||||||
@ -67,6 +67,60 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.form-search-filter-tags {
|
||||||
|
padding-top: 21px;
|
||||||
|
button {
|
||||||
|
margin: 10px 10px 0 0;
|
||||||
|
}
|
||||||
|
.btn.btn-info{
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
&.active {
|
||||||
|
background: #0397A8 !important;
|
||||||
|
color: #FFF !important;
|
||||||
|
}
|
||||||
|
&:not(.active) {
|
||||||
|
border: 1px solid #435F6F;
|
||||||
|
color: #435F6F !important;
|
||||||
|
background: #FFF;
|
||||||
|
padding: 3px 14px;
|
||||||
|
&:hover {
|
||||||
|
background: #0397A8 !important;
|
||||||
|
border: 1px solid #0397A8;
|
||||||
|
color: #FFF !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.directory-filters-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 30px -10px -10px;
|
||||||
|
padding: 20px 5px;
|
||||||
|
color: #000;
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
&.directory-filters-footer-warning {
|
||||||
|
background: #FFC107;
|
||||||
|
}
|
||||||
|
&.directory-filters-footer-info {
|
||||||
|
background: #d9edf7;
|
||||||
|
border: 1px solid #bce8f1;
|
||||||
|
}
|
||||||
|
.filter-footer-icon {
|
||||||
|
font-size: 35px;
|
||||||
|
line-height: 25px;
|
||||||
|
text-align: center;
|
||||||
|
color: #435F6F;
|
||||||
|
background: #FFF;
|
||||||
|
height: 25px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 32px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cards {
|
.cards {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -74,6 +128,12 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cards-no-results {
|
||||||
|
color: #000;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -85,10 +145,13 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: 15px 0;
|
margin: 15px 0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: #ffffff;
|
overflow: hidden;
|
||||||
&.card-archived {
|
&.card-archived {
|
||||||
filter: opacity(60%);
|
filter: opacity(60%);
|
||||||
}
|
}
|
||||||
|
> div:not(.card-status) {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-icons .fa {
|
.card-icons .fa {
|
||||||
@ -107,6 +170,26 @@
|
|||||||
background-position: center;
|
background-position: center;
|
||||||
border-radius: 4px 4px 0 0;
|
border-radius: 4px 4px 0 0;
|
||||||
}
|
}
|
||||||
|
.card-status {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px 12px;
|
||||||
|
color: #FFF;
|
||||||
|
min-height: 30px;
|
||||||
|
max-height: 30px;
|
||||||
|
&.card-status-professional {
|
||||||
|
background: #415F6E;
|
||||||
|
}
|
||||||
|
&.card-status-official, &.card-status-partner {
|
||||||
|
background: #90A1AA;
|
||||||
|
}
|
||||||
|
&.card-status-deprecated {
|
||||||
|
background: #EB0000;
|
||||||
|
}
|
||||||
|
&.card-status-featured, &.card-status-new {
|
||||||
|
background: #21A1B3;
|
||||||
|
}
|
||||||
|
}
|
||||||
.card-header {
|
.card-header {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
@ -143,6 +226,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.card-status-none + .card-header {
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
}
|
||||||
.card-body {
|
.card-body {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
padding: 44px 16px 24px 16px;
|
padding: 44px 16px 24px 16px;
|
@ -89,11 +89,6 @@
|
|||||||
@import "modal.less";
|
@import "modal.less";
|
||||||
}
|
}
|
||||||
|
|
||||||
@prev-module: false;
|
|
||||||
& when not(@prev-module) {
|
|
||||||
@import "module.less";
|
|
||||||
}
|
|
||||||
|
|
||||||
@prev-tooltip: false;
|
@prev-tooltip: false;
|
||||||
& when not(@prev-tooltip) {
|
& when not(@prev-tooltip) {
|
||||||
@import "tooltip.less";
|
@import "tooltip.less";
|
||||||
@ -206,7 +201,7 @@
|
|||||||
|
|
||||||
@prev-directory: false;
|
@prev-directory: false;
|
||||||
& when not(@prev-directory) {
|
& when not(@prev-directory) {
|
||||||
@import "directory.less";
|
@import "cards.less";
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "../css/select2Theme/build.less";
|
@import "../css/select2Theme/build.less";
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
// Modules list
|
|
||||||
.module-installed {
|
|
||||||
opacity: 0.5;
|
|
||||||
|
|
||||||
.label-success {
|
|
||||||
background-color: @background3;
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user