Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: messages inconsistencies #4174

Merged
merged 5 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extensions/messages/extend.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
(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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
4 changes: 4 additions & 0 deletions extensions/messages/js/src/common/extend.ts
Original file line number Diff line number Diff line change
@@ -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<boolean>('canSendAnyMessage'),
];
13 changes: 8 additions & 5 deletions extensions/messages/js/src/forum/components/DialogSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ export default class DialogSection<CustomAttrs extends IDialogStreamAttrs = IDia
<div className="DialogSection-header">
<Avatar user={recipient} />
<div className="DialogSection-header-info">
{(recipient && (
<Link href={app.route.user(recipient!)}>
<h2>{username(recipient)}</h2>
</Link>
)) || <h2>{username(recipient)}</h2>}
<h2 className="DialogSection-header-info-title">
{(recipient && <Link href={app.route.user(recipient!)}>{username(recipient)}</Link>) || username(recipient)}
{recipient && recipient.canSendAnyMessage() ? null : (
<span className="DialogSection-header-info-helperText">
{app.translator.trans('flarum-messages.forum.dialog_section.cannot_reply_text')}
</span>
)}
</h2>
<div className="badges">{listItems(recipient?.badges().toArray() || [])}</div>
</div>
<div className="DialogSection-header-actions">{this.actionItems().toArray()}</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ export default class MessageStream<CustomAttrs extends IDialogStreamAttrs = IDia

messages.forEach((message, index) => items.push(this.messageItem(message, index)));

if (ReplyPlaceholder) {
if (app.session.user!.canSendAnyMessage() && ReplyPlaceholder) {
items.push(
<div className="MessageStream-item" key="reply" /*data-index={this.attrs.state.count()}*/>
<div className="MessageStream-item" key="reply">
<ReplyPlaceholder
discussion={this.attrs.dialog}
onclick={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ export default class MessagesSidebar<CustomAttrs extends IMessagesSidebarAttrs =
items(): ItemList<Mithril.Children> {
const items = super.items();

const canSendAnyMessage = app.session.user!.attribute<boolean>('canSendAnyMessage');

items.remove('newDiscussion');

items.add(
Expand All @@ -27,9 +25,11 @@ export default class MessagesSidebar<CustomAttrs extends IMessagesSidebarAttrs =
onclick={() => {
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')}
</Button>,
10
);
Expand Down
8 changes: 5 additions & 3 deletions extensions/messages/js/src/forum/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -44,14 +45,14 @@ app.initializers.add('flarum-messages', () => {
});

extend(HeaderSecondary.prototype, 'items', function (items) {
if (app.session.user?.attribute<boolean>('canSendAnyMessage')) {
if (app.session.user?.canSendAnyMessage()) {
items.add('messages', <DialogsDropdown state={app.dropdownDialogs} />, 15);
}
});

// @ts-ignore
extend(UserControls, 'userControls', (items, user) => {
if (app.session.user?.attribute<boolean>('canSendAnyMessage')) {
extend(UserControls, 'userControls', (items, user: User) => {
if (app.session.user?.canSendAnyMessage()) {
items.add(
'sendMessage',
<Button
Expand All @@ -66,6 +67,7 @@ app.initializers.add('flarum-messages', () => {
.then(() => app.composer.show());
});
}}
helperText={user.canSendAnyMessage() ? null : app.translator.trans('flarum-messages.forum.user_controls.cannot_reply_text')}
>
{app.translator.trans('flarum-messages.forum.user_controls.send_message_button')}
</Button>
Expand Down
11 changes: 11 additions & 0 deletions extensions/messages/less/forum.less
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
8 changes: 5 additions & 3 deletions extensions/messages/locale/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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}
Expand Down
6 changes: 3 additions & 3 deletions extensions/tags/js/src/admin/addTagsPermissionScope.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ export default function () {
'tag',
<Dropdown
className="Dropdown--restrictByTag"
buttonClassName="Button Button--text"
buttonClassName="Button Button--link"
label={app.translator.trans('flarum-tags.admin.permissions.restrict_by_tag_heading')}
icon="fas fa-plus"
caretIcon={null}
>
{tags.map((tag) => (
<Button icon={true} onclick={() => tag.save({ isRestricted: true })}>
{[tagIcon(tag, { className: 'Button-icon' }), ' ', tag.name()]}
<Button icon={tagIcon(tag, { className: 'Button-icon' })} onclick={() => tag.save({ isRestricted: true })}>
{tag.name()}
</Button>
))}
</Dropdown>
Expand Down
28 changes: 23 additions & 5 deletions framework/core/js/src/common/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -56,7 +64,7 @@ export interface IButtonAttrs extends ComponentAttrs {
*/
export default class Button<CustomAttrs extends IButtonAttrs = IButtonAttrs> extends Component<CustomAttrs> {
view(vnode: Mithril.VnodeDOM<CustomAttrs, this>) {
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';
Expand All @@ -74,6 +82,7 @@ export default class Button<CustomAttrs extends IButtonAttrs = IButtonAttrs> ext
hasIcon: iconName,
disabled: disabled || loading,
loading: loading,
hasSubContent: !!this.getButtonSubContent(),
});

const buttonAttrs = {
Expand Down Expand Up @@ -104,12 +113,21 @@ export default class Button<CustomAttrs extends IButtonAttrs = IButtonAttrs> 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 && <Icon name={iconName} className="Button-icon" />,
children && <span className="Button-label">{children}</span>,
icon && (typeof icon === 'string' || icon === true ? <Icon name={icon} className="Button-icon" /> : icon),
children && (
<span className="Button-label">
<span className="Button-labelText">{children}</span>
{this.getButtonSubContent()}
</span>
),
this.attrs.loading && <LoadingIndicator size="small" display="inline" />,
];
}

protected getButtonSubContent(): Mithril.Children {
return this.attrs.helperText ? <span className="Button-helperText">{this.attrs.helperText}</span> : null;
}
}
11 changes: 10 additions & 1 deletion framework/core/js/src/common/components/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -157,11 +159,18 @@ export default class Dropdown<CustomAttrs extends IDropdownAttrs = IDropdownAttr
getButtonContent(children: Mithril.ChildArray): Mithril.ChildArray {
return [
this.attrs.icon ? <Icon name={this.attrs.icon} className="Button-icon" /> : '',
<span className="Button-label">{this.attrs.label}</span>,
<span className="Button-label">
<span className="Button-labelText">{this.attrs.label}</span>
{this.getButtonSubContent()}
</span>,
this.attrs.caretIcon ? <Icon name={this.attrs.caretIcon} className="Button-caret" /> : '',
];
}

protected getButtonSubContent(): Mithril.Children {
return this.attrs.helperText ? <span className="Button-helperText">{this.attrs.helperText}</span> : null;
}

getMenu(items: Mithril.Vnode<any, any>[]): Mithril.Vnode<any, any> {
return <ul className={'Dropdown-menu dropdown-menu ' + this.attrs.menuClassName}>{items}</ul>;
}
Expand Down
16 changes: 4 additions & 12 deletions framework/core/less/admin/PermissionsPage.less
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
}
}
Expand Down
6 changes: 6 additions & 0 deletions framework/core/less/common/Button.less
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion framework/core/less/common/Dropdown.less
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -51,6 +51,10 @@
flex-shrink: 0;
}

&.hasSubContent {
align-items: flex-start;
}

&.disabled {
opacity: 0.4;
background: none !important;
Expand Down
Loading