Enh/5668 space sort order (#6247)

* Enh #5668: Allow Admin to sort the Spaces in a custom order

* Enh #5668: Allow Admin to sort the Spaces in a custom order

* Enh #5668: Allow Admin to sort the Spaces in a custom order

* Sort order field ReadOnly and added defaultOrderBy()

* Removed required sort_order attribute in Space model

* Space admin grid more compact

* Space admin grid more compact

---------

Co-authored-by: Lucas Bartholemy <luke-@users.noreply.github.com>
This commit is contained in:
Marc Farré 2023-05-06 09:27:03 +02:00 committed by GitHub
parent 6fe42f6772
commit 2720a372a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 169 additions and 94 deletions

View File

@ -17,6 +17,7 @@ HumHub Changelog
- Fix #6216: Spaces icon in admin menu
- Fix #6229: Bug on saving forms: Zend OPcache API is restricted by "restrict_api"
- Enh #6240: Add ability to set showAtDashboard in SpaceMembership::addMember method
- Enh #5668: Allow Admin to sort the Spaces in a custom order
- Enh #29: AutoStart Tour for new Users
- Fix #6243: Do not send notification when ApprovalRequest is not valid
- Enh #6215: Added `LongRunningActiveJob` to avoid timeout for long running queue jobs

View File

@ -8,10 +8,12 @@
namespace humhub\modules\admin\grid;
use humhub\libs\Helpers;
use humhub\modules\space\models\Space;
use humhub\widgets\Label;
use Yii;
use yii\bootstrap\Html;
use humhub\modules\space\models\Space;
use humhub\libs\Helpers;
/**
* TitleColumn
*
@ -33,7 +35,9 @@ class SpaceTitleColumn extends SpaceBaseColumn
}
if ($this->label === null) {
$this->label = Yii::t('SpaceModule.base', 'Name');
$this->label = Space::find()->where(['not', ['sort_order' => 100]])->count() ?
Yii::t('SpaceModule.base', 'Name / Sort order') :
Yii::t('SpaceModule.base', 'Name');
}
}
@ -46,11 +50,14 @@ class SpaceTitleColumn extends SpaceBaseColumn
$badge = '';
if ($space->status == Space::STATUS_ARCHIVED) {
$badge = '&nbsp;<span class="badge">'.Yii::t('SpaceModule.base', 'Archived').'</span>';
$badge = '&nbsp;<span class="badge">' . Yii::t('SpaceModule.base', 'Archived') . '</span>';
}
return '<div>' . Html::encode($space->name) . $badge . '<br> ' .
'<small>' . Html::encode(Helpers::trimText($space->description, 100)) . '</small></div>';
return Html::tag('div',
Html::encode($space->name) . $badge .
($space->sort_order === 100 ? '' : ' ' . Label::defaultType($space->sort_order)) .
'<br> ' . '<small>' . Html::encode(Helpers::trimText($space->description, 100)) . '</small>'
);
}
}

View File

@ -8,11 +8,11 @@
namespace humhub\modules\admin\models;
use humhub\modules\space\models\Membership;
use humhub\modules\space\models\Space;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use humhub\modules\space\models\Space;
use humhub\modules\space\models\Membership;
/**
* SpaceSearch for administration
@ -86,12 +86,16 @@ class SpaceSearch extends Space
$dataProvider->setSort([
'attributes' => [
'id',
'sort_order',
'name',
'visibility',
'join_policy',
'memberCount',
]
]);
$dataProvider->sort->defaultOrder = ['sort_order' => SORT_ASC, 'name' => SORT_ASC];
$dataProvider->sort->attributes['ownerUser.profile.lastname'] = [
'asc' => ['profile.lastname' => SORT_ASC],
'desc' => ['profile.lastname' => SORT_DESC],

View File

@ -1,20 +1,20 @@
<?php
use humhub\modules\admin\grid\SpaceActionColumn;
use humhub\modules\admin\grid\SpaceImageColumn;
use humhub\modules\admin\grid\SpaceTitleColumn;
use humhub\modules\admin\models\SpaceSearch;
use humhub\modules\admin\widgets\SpaceGridView;
use humhub\modules\space\permissions\CreatePrivateSpace;
use humhub\modules\space\permissions\CreatePublicSpace;
use humhub\modules\user\grid\DisplayNameColumn;
use humhub\modules\user\grid\ImageColumn;
use humhub\widgets\ModalButton;
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use humhub\modules\admin\widgets\SpaceGridView;
use humhub\modules\admin\grid\SpaceActionColumn;
use humhub\modules\admin\grid\SpaceTitleColumn;
use humhub\modules\admin\grid\SpaceImageColumn;
use humhub\modules\admin\models\SpaceSearch;
use yii\helpers\Html;
use yii\helpers\Url;
/* @var $searchModel SpaceSearch*/
/* @var $searchModel SpaceSearch */
?>
<?php if (Yii::$app->user->can([CreatePublicSpace::class, CreatePrivateSpace::class])) : ?>

View File

@ -106,4 +106,13 @@ class ActiveQuerySpace extends AbstractActiveQueryContentContainer
return $this;
}
/**
* @return ActiveQuerySpace
*/
public function defaultOrderBy(): ActiveQuerySpace
{
$this->orderBy(['space.sort_order' => SORT_ASC, 'space.name' => SORT_ASC]);
return $this;
}
}

View File

@ -116,12 +116,16 @@ class SpaceDirectoryQuery extends ActiveQuerySpace
public function order(): SpaceDirectoryQuery
{
switch (SpaceDirectoryFilters::getValue('sort')) {
case 'sortOrder':
$this->defaultOrderBy();
break;
case 'name':
$this->addOrderBy('space.name');
break;
case 'newer':
$this->addOrderBy('space.created_at DESC');
$this->addOrderBy(['space.created_at' => SORT_DESC]);
break;
case 'older':

View File

@ -0,0 +1,25 @@
<?php
use yii\db\Migration;
/**
* Handles adding columns to table `{{%space}}`.
*/
class m230419_102455_add_sort_order_column_to_space_table extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('{{%space}}', 'sort_order', $this->integer()->defaultValue(100)->notNull()->after('status'));
}
/**
* {@inheritdoc}
*/
public function safeDown()
{
echo "m230419_102455_add_sort_order_column_to_space_table cannot be reverted.\n";
}
}

View File

@ -8,6 +8,7 @@
namespace humhub\modules\space\models;
use humhub\modules\admin\permissions\ManageSpaces;
use humhub\modules\space\components\UrlValidator;
use humhub\modules\space\Module;
use Yii;
@ -62,12 +63,19 @@ class AdvancedSettings extends Model
*/
public $hideFollowers = false;
/**
* @var int
*/
public $sortOrder;
/**
* @inheritdoc
*/
public function rules()
{
return [
[['sortOrder'], 'required'],
[['sortOrder'], 'integer'],
[['indexUrl', 'indexGuestUrl'], 'string'],
[['hideMembers', 'hideActivities', 'hideAbout', 'hideFollowers'], 'boolean'],
['url', UrlValidator::class, 'space' => $this->space]
@ -112,10 +120,11 @@ class AdvancedSettings extends Model
$this->indexUrl = $settings->get('indexUrl', null);
$this->indexGuestUrl = $settings->get('indexGuestUrl', null);
$this->hideMembers = $settings->get('hideMembers', $this->hideMembers);
$this->hideAbout = $settings->get('hideAbout', $module->hideAboutPage);
$this->hideActivities = $settings->get('hideActivities', $this->hideActivities);
$this->hideFollowers = $settings->get('hideFollowers', $this->hideFollowers);
$this->hideMembers = (bool)$settings->get('hideMembers', $this->hideMembers);
$this->hideAbout = (bool)$settings->get('hideAbout', $module->hideAboutPage);
$this->hideActivities = (bool)$settings->get('hideActivities', $this->hideActivities);
$this->hideFollowers = (bool)$settings->get('hideFollowers', $this->hideFollowers);
$this->sortOrder = $this->space->sort_order;
}
/**
@ -148,6 +157,10 @@ class AdvancedSettings extends Model
}
}
if (Yii::$app->user->can(ManageSpaces::class)) {
$this->space->sort_order = $this->sortOrder;
}
$this->space->save();
if (!empty($this->indexUrl)) {

View File

@ -9,8 +9,8 @@
namespace humhub\modules\space\models;
use humhub\components\ActiveRecord;
use humhub\modules\user\models\User;
use humhub\modules\content\models\Content;
use humhub\modules\user\models\User;
use Yii;
use yii\db\Query;
@ -114,8 +114,8 @@ class Membership extends ActiveRecord
}
/**
* @since 1.13
* @return bool
* @since 1.13
*/
public function isPrivileged(): bool
{
@ -273,13 +273,11 @@ class Membership extends ActiveRecord
}
if (Yii::$app->getModule('space')->settings->get('spaceOrder') == 0) {
$query->orderBy('name ASC');
$query->defaultOrderBy();
} else {
$query->orderBy('last_visit DESC');
$query->orderBy(['space_membership.last_visit' => SORT_DESC]);
}
$query->orderBy(['name' => SORT_ASC]);
return $query;
}
@ -305,9 +303,9 @@ class Membership extends ActiveRecord
$query = Membership::find();
if (Yii::$app->getModule('space')->settings->get('spaceOrder') == 0) {
$query->orderBy('space.name ASC');
$query->orderBy(['space.sort_order' => SORT_ASC, 'space.name' => SORT_ASC]);
} else {
$query->orderBy('space_membership.last_visit DESC');
$query->orderBy(['space_membership.last_visit' => SORT_DESC]);
}
$query->joinWith('space')->where(['space_membership.user_id' => $user->id]);
@ -380,4 +378,5 @@ class Membership extends ActiveRecord
public function isCurrentUser(): bool
{
return !Yii::$app->user->isGuest && Yii::$app->user->identity->id === $this->user_id;
}}
}
}

View File

@ -8,29 +8,29 @@
namespace humhub\modules\space\models;
use humhub\components\behaviors\GUID;
use humhub\modules\content\components\ContentContainerActiveRecord;
use humhub\modules\content\components\ContentContainerSettingsManager;
use humhub\modules\search\interfaces\Searchable;
use humhub\modules\content\models\Content;
use humhub\modules\search\events\SearchAddEvent;
use humhub\modules\search\interfaces\Searchable;
use humhub\modules\search\jobs\DeleteDocument;
use humhub\modules\search\jobs\UpdateDocument;
use humhub\modules\space\behaviors\SpaceModelMembership;
use humhub\modules\space\activities\Created;
use humhub\modules\space\behaviors\SpaceController;
use humhub\modules\space\behaviors\SpaceModelMembership;
use humhub\modules\space\components\ActiveQuerySpace;
use humhub\modules\space\components\UrlValidator;
use humhub\modules\space\Module;
use humhub\modules\user\behaviors\Followable;
use humhub\components\behaviors\GUID;
use humhub\modules\space\permissions\CreatePrivateSpace;
use humhub\modules\space\permissions\CreatePublicSpace;
use humhub\modules\space\components\UrlValidator;
use humhub\modules\space\activities\Created;
use humhub\modules\content\components\ContentContainerActiveRecord;
use humhub\modules\content\models\Content;
use humhub\modules\user\helpers\AuthHelper;
use humhub\modules\user\models\GroupSpace;
use humhub\modules\user\models\User;
use humhub\modules\user\models\Follow;
use humhub\modules\user\models\Invite;
use humhub\modules\space\widgets\Wall;
use humhub\modules\user\behaviors\Followable;
use humhub\modules\user\helpers\AuthHelper;
use humhub\modules\user\models\Follow;
use humhub\modules\user\models\GroupSpace;
use humhub\modules\user\models\Invite;
use humhub\modules\user\models\User;
use humhub\modules\user\models\User as UserModel;
use Yii;
@ -46,6 +46,7 @@ use Yii;
* @property integer $join_policy
* @property integer $visibility
* @property integer $status
* @property integer $sort_order
* @property string $created_at
* @property integer $created_by
* @property string $updated_at
@ -116,7 +117,7 @@ class Space extends ContentContainerActiveRecord implements Searchable
public function rules()
{
$rules = [
[['join_policy', 'visibility', 'status', 'auto_add_new_members', 'default_content_visibility'], 'integer'],
[['join_policy', 'visibility', 'status', 'sort_order', 'auto_add_new_members', 'default_content_visibility'], 'integer'],
[['name'], 'required'],
[['description', 'about', 'color'], 'string'],
[['tagsField', 'blockedUsersField'], 'safe'],

View File

@ -1,10 +1,12 @@
<?php
use humhub\modules\admin\permissions\ManageSpaces;
use humhub\modules\space\models\AdvancedSettings;
use humhub\modules\space\models\Space;
use humhub\modules\space\modules\manage\widgets\DefaultMenu;
use humhub\widgets\Button;
use humhub\modules\ui\form\widgets\ActiveForm;
use humhub\modules\ui\form\widgets\SortOrderField;
use humhub\widgets\Button;
use yii\helpers\Url;
/* @var $model AdvancedSettings */
@ -33,6 +35,13 @@ use yii\helpers\Url;
<?= $form->field($model, 'hideFollowers')->checkbox(); ?>
<?= $form->field($model, 'indexUrl')->dropDownList($indexModuleSelection) ?>
<?= $form->field($model, 'indexGuestUrl')->dropDownList($indexModuleSelection) ?>
<?php if (Yii::$app->user->can(ManageSpaces::class)) : ?>
<?= $form->field($model, 'sortOrder')->widget(SortOrderField::class) ?>
<?php else: ?>
<?= $form->field($model, 'sortOrder')->widget(SortOrderField::class, [
'options' => ['disabled' => 'disabled']
])->hint(Yii::t('SpaceModule.manage', 'Only global administrators can change this value')) ?>
<?php endif; ?>
<?= Button::save()->submit() ?>
<?= Button::danger(Yii::t('base', 'Delete'))->right()->link($space->createUrl('delete'))->visible($space->canDelete()) ?>

View File

@ -27,45 +27,46 @@ class SpaceDirectoryFilters extends DirectoryFilters
protected function initDefaultFilters()
{
$this->addFilter('keyword', [
'title' => Yii::t('SpaceModule.base', 'Find Spaces by their description or by their tags'),
'placeholder' => Yii::t('SpaceModule.base', 'Search...'),
'type' => 'input',
'wrapperClass' => 'col-md-6 form-search-filter-keyword',
'afterInput' => Html::submitButton('<span class="fa fa-search"></span>', ['class' => 'form-button-search']),
'sortOrder' => 100,
]);
'title' => Yii::t('SpaceModule.base', 'Find Spaces by their description or by their tags'),
'placeholder' => Yii::t('SpaceModule.base', 'Search...'),
'type' => 'input',
'wrapperClass' => 'col-md-6 form-search-filter-keyword',
'afterInput' => Html::submitButton('<span class="fa fa-search"></span>', ['class' => 'form-button-search']),
'sortOrder' => 100,
]);
$this->addFilter('sort', [
'title' => Yii::t('SpaceModule.base', 'Sorting'),
'type' => 'dropdown',
'options' => [
'name' => Yii::t('SpaceModule.base', 'By Name'),
'newer' => Yii::t('SpaceModule.base', 'Newest first'),
'older' => Yii::t('SpaceModule.base', 'Oldest first'),
],
'sortOrder' => 200,
]);
'title' => Yii::t('SpaceModule.base', 'Sorting'),
'type' => 'dropdown',
'options' => [
'sortOrder' => '',
'name' => Yii::t('SpaceModule.base', 'By Name'),
'newer' => Yii::t('SpaceModule.base', 'Newest first'),
'older' => Yii::t('SpaceModule.base', 'Oldest first'),
],
'sortOrder' => 200,
]);
$this->addFilter('connection', [
'title' => Yii::t('SpaceModule.base', 'Status'),
'type' => 'dropdown',
'options' => [
'' => Yii::t('SpaceModule.base', 'Any'),
'member' => Yii::t('SpaceModule.base', 'Member'),
'follow' => Yii::t('SpaceModule.base', 'Following'),
'none' => Yii::t('SpaceModule.base', 'Neither..nor'),
'separator' => '———————————',
'archived' => Yii::t('SpaceModule.base', 'Archived'),
],
'sortOrder' => 300,
]);
'title' => Yii::t('SpaceModule.base', 'Status'),
'type' => 'dropdown',
'options' => [
'' => Yii::t('SpaceModule.base', 'Any'),
'member' => Yii::t('SpaceModule.base', 'Member'),
'follow' => Yii::t('SpaceModule.base', 'Following'),
'none' => Yii::t('SpaceModule.base', 'Neither..nor'),
'separator' => '———————————',
'archived' => Yii::t('SpaceModule.base', 'Archived'),
],
'sortOrder' => 300,
]);
}
public static function getDefaultValue(string $filter): string
{
switch ($filter) {
case 'sort':
return 'name';
return 'sortOrder';
}
return parent::getDefaultValue($filter);

View File

@ -9,17 +9,17 @@
namespace humhub\modules\user\models;
use humhub\components\behaviors\PolymorphicRelation;
use humhub\modules\activity\models\Activity;
use humhub\modules\space\models\Space;
use humhub\modules\user\activities\UserFollow;
use humhub\modules\user\components\ActiveQueryUser;
use humhub\modules\user\events\FollowEvent;
use humhub\modules\user\notifications\Followed;
use Yii;
use yii\base\InvalidConfigException;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\db\Query;
use humhub\modules\user\components\ActiveQueryUser;
use humhub\modules\user\events\FollowEvent;
use humhub\modules\activity\models\Activity;
use humhub\modules\space\models\Space;
/**
* This is the model class for table "user_follow".
@ -98,15 +98,15 @@ class Follow extends ActiveRecord
{
if ($insert && $this->send_notifications && $this->object_model == User::class) {
Followed::instance()
->from($this->user)
->about($this)
->send($this->getTarget());
->from($this->user)
->about($this)
->send($this->getTarget());
UserFollow::instance()
->from($this->user)
->container($this->user)
->about($this)
->save();
->from($this->user)
->container($this->user)
->about($this)
->save();
}
$this->trigger(Follow::EVENT_FOLLOWING_CREATED, new FollowEvent(['user' => $this->user, 'target' => $this->getTarget()]));
@ -119,7 +119,7 @@ class Follow extends ActiveRecord
*/
public function beforeDelete()
{
if($this->getTarget()) {
if ($this->getTarget()) {
$this->trigger(Follow::EVENT_FOLLOWING_REMOVED, new FollowEvent(['user' => $this->user, 'target' => $this->getTarget()]));
// ToDo: Handle this via event of User Module
@ -148,7 +148,7 @@ class Follow extends ActiveRecord
if ($targetClass != "" && is_subclass_of($targetClass, ActiveRecord::class)) {
return $targetClass::findOne(['id' => $this->object_id]);
}
} catch(\Exception $e) {
} catch (\Exception $e) {
// Avoid errors in integrity check
Yii::error($e);
}
@ -167,8 +167,8 @@ class Follow extends ActiveRecord
public static function getFollowedSpacesQuery(User $user, $withNotifications = null)
{
$subQuery = self::find()
->where(['user_follow.user_id' => $user->id, 'user_follow.object_model' => Space::class])
->andWhere('user_follow.object_id=space.id');
->where(['user_follow.user_id' => $user->id, 'user_follow.object_model' => Space::class])
->andWhere('user_follow.object_id=space.id');
if ($withNotifications === true) {
$subQuery->andWhere(['user_follow.send_notifications' => 1]);
@ -176,7 +176,9 @@ class Follow extends ActiveRecord
$subQuery->andWhere(['user_follow.send_notifications' => 0]);
}
return Space::find()->where(['exists', $subQuery]);
return Space::find()
->where(['exists', $subQuery])
->defaultOrderBy();
}
/**
@ -217,8 +219,8 @@ class Follow extends ActiveRecord
->where(['user_follow.user_id' => $user->id])
->indexBy('id')
->andWhere($containerClass
? ['user_follow.object_model' => $containerClass]
: ['OR', ['user_follow.object_model' => Space::class], ['user_follow.object_model' => User::class]]);
? ['user_follow.object_model' => $containerClass]
: ['OR', ['user_follow.object_model' => Space::class], ['user_follow.object_model' => User::class]]);
}
/**
@ -232,8 +234,8 @@ class Follow extends ActiveRecord
public static function getFollowersQuery(ActiveRecord $target, $withNotifications = null)
{
$subQuery = self::find()
->where(['user_follow.object_model' => $target->className(), 'user_follow.object_id' => $target->getPrimaryKey()])
->andWhere('user_follow.user_id=user.id');
->where(['user_follow.object_model' => $target->className(), 'user_follow.object_id' => $target->getPrimaryKey()])
->andWhere('user_follow.user_id=user.id');
if ($withNotifications === true) {
$subQuery->andWhere(['user_follow.send_notifications' => 1]);