From 89ff98444640b13ffbd79faf91f1363dafbc5d6b Mon Sep 17 00:00:00 2001 From: Sami Mazouz Date: Fri, 31 Jan 2025 12:57:45 +0100 Subject: [PATCH] fix: messages inconsistencies (#4174) * fix: messages inconsistencies * fix * chore: message at the page * fix: permission grid styling broken * fix --- extensions/messages/extend.php | 2 +- .../messages/js/{src => }/@types/shims.d.ts | 6 ++++ extensions/messages/js/src/common/extend.ts | 4 +++ .../js/src/forum/components/DialogSection.tsx | 13 +++++---- .../js/src/forum/components/MessageStream.tsx | 4 +-- .../src/forum/components/MessagesSidebar.tsx | 8 +++--- extensions/messages/js/src/forum/index.tsx | 8 ++++-- extensions/messages/less/forum.less | 11 ++++++++ extensions/messages/locale/en.yml | 8 ++++-- .../js/src/admin/addTagsPermissionScope.tsx | 6 ++-- .../core/js/src/common/components/Button.tsx | 28 +++++++++++++++---- .../js/src/common/components/Dropdown.tsx | 11 +++++++- .../core/less/admin/PermissionsPage.less | 16 +++-------- framework/core/less/common/Button.less | 6 ++++ framework/core/less/common/Dropdown.less | 6 +++- 15 files changed, 97 insertions(+), 40 deletions(-) rename extensions/messages/js/{src => }/@types/shims.d.ts (82%) diff --git a/extensions/messages/extend.php b/extensions/messages/extend.php index bac98a3ae..84d0be376 100644 --- a/extensions/messages/extend.php +++ b/extensions/messages/extend.php @@ -51,7 +51,7 @@ return [ (new Extend\ApiResource(Resource\UserResource::class)) ->fields(fn () => [ Schema\Boolean::make('canSendAnyMessage') - ->get(fn (object $model, Context $context) => $context->getActor()->can('sendAnyMessage')), + ->get(fn (User $user, Context $context) => $user->can('sendAnyMessage')), Schema\Integer::make('messageCount') ->get(function (object $model, Context $context) { return Dialog::whereVisibleTo($context->getActor()) diff --git a/extensions/messages/js/src/@types/shims.d.ts b/extensions/messages/js/@types/shims.d.ts similarity index 82% rename from extensions/messages/js/src/@types/shims.d.ts rename to extensions/messages/js/@types/shims.d.ts index 42e42031b..b5fc4de82 100644 --- a/extensions/messages/js/src/@types/shims.d.ts +++ b/extensions/messages/js/@types/shims.d.ts @@ -19,3 +19,9 @@ declare module 'flarum/forum/states/ComposerState' { composingMessageTo(dialog: Dialog): boolean; } } + +declare module 'flarum/common/models/User' { + export default interface User { + canSendAnyMessage(): boolean; + } +} diff --git a/extensions/messages/js/src/common/extend.ts b/extensions/messages/js/src/common/extend.ts index fc325472d..59286e0b2 100644 --- a/extensions/messages/js/src/common/extend.ts +++ b/extensions/messages/js/src/common/extend.ts @@ -1,9 +1,13 @@ import DialogMessage from './models/DialogMessage'; import Dialog from './models/Dialog'; import Extend from 'flarum/common/extenders'; +import User from 'flarum/common/models/User'; export default [ new Extend.Store() .add('dialogs', Dialog) // .add('dialog-messages', DialogMessage), // + + new Extend.Model(User) // + .attribute('canSendAnyMessage'), ]; diff --git a/extensions/messages/js/src/forum/components/DialogSection.tsx b/extensions/messages/js/src/forum/components/DialogSection.tsx index 52cea46dc..b7d431a6c 100644 --- a/extensions/messages/js/src/forum/components/DialogSection.tsx +++ b/extensions/messages/js/src/forum/components/DialogSection.tsx @@ -42,11 +42,14 @@ export default class DialogSection
- {(recipient && ( - -

{username(recipient)}

- - )) ||

{username(recipient)}

} +

+ {(recipient && {username(recipient)}) || username(recipient)} + {recipient && recipient.canSendAnyMessage() ? null : ( + + {app.translator.trans('flarum-messages.forum.dialog_section.cannot_reply_text')} + + )} +

{listItems(recipient?.badges().toArray() || [])}
{this.actionItems().toArray()}
diff --git a/extensions/messages/js/src/forum/components/MessageStream.tsx b/extensions/messages/js/src/forum/components/MessageStream.tsx index 912dfb231..45fe8881d 100644 --- a/extensions/messages/js/src/forum/components/MessageStream.tsx +++ b/extensions/messages/js/src/forum/components/MessageStream.tsx @@ -106,9 +106,9 @@ export default class MessageStream items.push(this.messageItem(message, index))); - if (ReplyPlaceholder) { + if (app.session.user!.canSendAnyMessage() && ReplyPlaceholder) { items.push( -
+
{ diff --git a/extensions/messages/js/src/forum/components/MessagesSidebar.tsx b/extensions/messages/js/src/forum/components/MessagesSidebar.tsx index 6a04c804c..4ac046e0b 100644 --- a/extensions/messages/js/src/forum/components/MessagesSidebar.tsx +++ b/extensions/messages/js/src/forum/components/MessagesSidebar.tsx @@ -14,8 +14,6 @@ export default class MessagesSidebar { const items = super.items(); - const canSendAnyMessage = app.session.user!.attribute('canSendAnyMessage'); - items.remove('newDiscussion'); items.add( @@ -27,9 +25,11 @@ export default class MessagesSidebar { return this.newMessageAction(); }} - disabled={!canSendAnyMessage} + disabled={!app.session.user!.canSendAnyMessage()} > - {app.translator.trans('flarum-messages.forum.messages_page.new_message_button')} + {app.session.user!.canSendAnyMessage() + ? app.translator.trans('flarum-messages.forum.messages_page.send_message_button') + : app.translator.trans('flarum-messages.forum.messages_page.cannot_send_message_button')} , 10 ); diff --git a/extensions/messages/js/src/forum/index.tsx b/extensions/messages/js/src/forum/index.tsx index 35e735948..6be692a7d 100644 --- a/extensions/messages/js/src/forum/index.tsx +++ b/extensions/messages/js/src/forum/index.tsx @@ -8,6 +8,7 @@ import Button from 'flarum/common/components/Button'; import type Dialog from '../common/models/Dialog'; import DialogsDropdown from './components/DialogsDropdown'; import DialogListState from './states/DialogListState'; +import type User from 'flarum/common/models/User'; export { default as extend } from './extend'; @@ -44,14 +45,14 @@ app.initializers.add('flarum-messages', () => { }); extend(HeaderSecondary.prototype, 'items', function (items) { - if (app.session.user?.attribute('canSendAnyMessage')) { + if (app.session.user?.canSendAnyMessage()) { items.add('messages', , 15); } }); // @ts-ignore - extend(UserControls, 'userControls', (items, user) => { - if (app.session.user?.attribute('canSendAnyMessage')) { + extend(UserControls, 'userControls', (items, user: User) => { + if (app.session.user?.canSendAnyMessage()) { items.add( 'sendMessage', diff --git a/extensions/messages/less/forum.less b/extensions/messages/less/forum.less index 8770d9985..e63050011 100644 --- a/extensions/messages/less/forum.less +++ b/extensions/messages/less/forum.less @@ -232,6 +232,17 @@ gap: 6px; } +.DialogSection-header-info-title { + display: flex; + flex-direction: column; +} + +.DialogSection-header-info-helperText { + font-size: 0.8rem; + font-weight: normal; + color: var(--control-color); +} + .DialogSection-back { display: flex; diff --git a/extensions/messages/locale/en.yml b/extensions/messages/locale/en.yml index 802cc288b..34c891567 100644 --- a/extensions/messages/locale/en.yml +++ b/extensions/messages/locale/en.yml @@ -22,6 +22,7 @@ flarum-messages: dialog_section: back_label: Go back + cannot_reply_text: This user cannot reply controls: details_button: Details controls_toggle_label: Dialog control actions @@ -42,14 +43,14 @@ flarum-messages: oldest_button: Oldest messages_page: - empty_text: You have no messages yet. When you send or receive messages, they - will appear here. + cannot_send_message_button: Can't Send a Message + empty_text: No new messages hero: title: Messages subtitle: Your private conversations with other users mark_all_as_read_tooltip: Mark all as read - new_message_button: Send a Message refresh_tooltip: Refresh + send_message_button: Send a Message stream: load_previous_button: Load previous messages start_of_the_conversation: Start of the conversation @@ -64,6 +65,7 @@ flarum-messages: user_controls: send_message_button: Send a message + cannot_reply_text: This user cannot reply notifications: message_received_text: Message Received notification from {user} diff --git a/extensions/tags/js/src/admin/addTagsPermissionScope.tsx b/extensions/tags/js/src/admin/addTagsPermissionScope.tsx index 1cdb1c46b..6d1632676 100644 --- a/extensions/tags/js/src/admin/addTagsPermissionScope.tsx +++ b/extensions/tags/js/src/admin/addTagsPermissionScope.tsx @@ -78,14 +78,14 @@ export default function () { 'tag', {tags.map((tag) => ( - ))} diff --git a/framework/core/js/src/common/components/Button.tsx b/framework/core/js/src/common/components/Button.tsx index 641c46f7e..390c5f849 100644 --- a/framework/core/js/src/common/components/Button.tsx +++ b/framework/core/js/src/common/components/Button.tsx @@ -11,8 +11,10 @@ export interface IButtonAttrs extends ComponentAttrs { * Class(es) of an optional icon to be rendered within the button. * * If provided, the button will gain a `has-icon` class. + * + * You may also provide a rendered icon element directly. */ - icon?: string; + icon?: string | boolean | Mithril.Children; /** * Disables button from user input. * @@ -42,6 +44,12 @@ export interface IButtonAttrs extends ComponentAttrs { * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type */ type?: string; + /** + * Helper text. Displayed under the button label. + * + * Default: `null` + */ + helperText?: Mithril.Children; } /** @@ -56,7 +64,7 @@ export interface IButtonAttrs extends ComponentAttrs { */ export default class Button extends Component { view(vnode: Mithril.VnodeDOM) { - let { type, 'aria-label': ariaLabel, icon: iconName, disabled, loading, className, class: _class, ...attrs } = this.attrs; + let { type, 'aria-label': ariaLabel, icon: iconName, disabled, loading, className, class: _class, helperText, ...attrs } = this.attrs; // If no `type` attr provided, set to "button" type ||= 'button'; @@ -74,6 +82,7 @@ export default class Button ext hasIcon: iconName, disabled: disabled || loading, loading: loading, + hasSubContent: !!this.getButtonSubContent(), }); const buttonAttrs = { @@ -104,12 +113,21 @@ export default class Button ext * Get the template for the button's content. */ protected getButtonContent(children: Mithril.Children): Mithril.ChildArray { - const iconName = this.attrs.icon; + const icon = this.attrs.icon; return [ - iconName && , - children && {children}, + icon && (typeof icon === 'string' || icon === true ? : icon), + children && ( + + {children} + {this.getButtonSubContent()} + + ), this.attrs.loading && , ]; } + + protected getButtonSubContent(): Mithril.Children { + return this.attrs.helperText ? {this.attrs.helperText} : null; + } } diff --git a/framework/core/js/src/common/components/Dropdown.tsx b/framework/core/js/src/common/components/Dropdown.tsx index 899ac8412..3e5d43fc8 100644 --- a/framework/core/js/src/common/components/Dropdown.tsx +++ b/framework/core/js/src/common/components/Dropdown.tsx @@ -19,6 +19,8 @@ export interface IDropdownAttrs extends ComponentAttrs { caretIcon?: string; /** The label of the dropdown toggle button. Defaults to 'Controls'. */ label: Mithril.Children; + /** The helper text to display under the button label. */ + helperText: Mithril.Children; /** The label used to describe the dropdown toggle button to assistive readers. Defaults to 'Toggle dropdown menu'. */ accessibleToggleLabel?: string; /** An optional tooltip to show when hovering over the dropdown toggle button. */ @@ -157,11 +159,18 @@ export default class Dropdown : '', - {this.attrs.label}, + + {this.attrs.label} + {this.getButtonSubContent()} + , this.attrs.caretIcon ? : '', ]; } + protected getButtonSubContent(): Mithril.Children { + return this.attrs.helperText ? {this.attrs.helperText} : null; + } + getMenu(items: Mithril.Vnode[]): Mithril.Vnode { return
    {items}
; } diff --git a/framework/core/less/admin/PermissionsPage.less b/framework/core/less/admin/PermissionsPage.less index 514028d22..8c2a40862 100644 --- a/framework/core/less/admin/PermissionsPage.less +++ b/framework/core/less/admin/PermissionsPage.less @@ -94,23 +94,19 @@ } } .Dropdown { - display: block; - .Dropdown-toggle { width: 100%; - display: block; - text-align: left; - float: none; + margin: -2px 0; } .Dropdown-menu { - margin: 0; + margin: 6px 0 0; } } .Button { text-decoration: none; .Badge { - margin: -3px 2px -3px 0; + margin: 0 2px 0 0; } } td:not(:hover) .Select-caret, @@ -126,12 +122,8 @@ margin: -1px 0; } .PermissionDropdown { - .Dropdown-toggle { - padding: 5px 0; - margin: -5px 0; - } .Badge { - margin: -3px 3px -3px 0; + margin: 0 3px 0 0; box-shadow: none; } } diff --git a/framework/core/less/common/Button.less b/framework/core/less/common/Button.less index 7f468ed49..2734ba876 100644 --- a/framework/core/less/common/Button.less +++ b/framework/core/less/common/Button.less @@ -259,6 +259,12 @@ line-height: inherit; overflow: hidden; text-overflow: ellipsis; + display: flex; + flex-direction: column; +} +.Button-helperText { + font-size: 0.73rem; + color: var(--muted-more-color); } .Button-icon { line-height: inherit; diff --git a/framework/core/less/common/Dropdown.less b/framework/core/less/common/Dropdown.less index aa73d9024..56b650b31 100644 --- a/framework/core/less/common/Dropdown.less +++ b/framework/core/less/common/Dropdown.less @@ -27,8 +27,8 @@ > a, > button, > span { padding: 8px 15px; display: flex; - align-items: center; gap: 9px; + align-items: center; width: 100%; color: var(--text-color); border-radius: 0; @@ -51,6 +51,10 @@ flex-shrink: 0; } + &.hasSubContent { + align-items: flex-start; + } + &.disabled { opacity: 0.4; background: none !important;