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

Merge upstream changes up to 28411acebb5626acf43b44a7b6c33ac783156f72 #2809

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
664bef3
Fix styling issues with notification settings and mobile borders (#31…
vmstan Aug 8, 2024
a207a1f
Disable stylelint rules that are conflicting with Prettier (#31339)
renchap Aug 8, 2024
389549e
Fix list creation textbox styling (#31348)
vmstan Aug 8, 2024
f045ef8
Update dependency eslint-plugin-jsdoc to v50 (#31330)
renovate[bot] Aug 8, 2024
6e01a23
Update dependency eslint-plugin-promise to v7 (#31120)
renovate[bot] Aug 8, 2024
2095d0f
Update notification labels for mentions (#31304)
renchap Aug 8, 2024
6ca731e
Change unread notification count to only cover the selected notificat…
ClearlyClaire Aug 8, 2024
9538d9c
Fix post filter & report styling (#31349)
vmstan Aug 9, 2024
9bae237
Change confirmation prompt on trending management (#19626)
tribela Aug 9, 2024
994ef16
Bust CDN cache on media deletion (#31353)
ClearlyClaire Aug 9, 2024
e29c401
Add lang attribute on preview card title (#31303)
c960657 Aug 9, 2024
cbdd8ed
Revamp notification policy options (#31343)
ClearlyClaire Aug 9, 2024
8a5b57f
Revert "Support JSON-LD named graph (#31288)" (#31355)
ClearlyClaire Aug 9, 2024
1701575
Add option to ignore filtered notifications to the web interface (#31…
ClearlyClaire Aug 9, 2024
eaedd52
Fix incorrect rate limit on PUT requests (#31356)
ClearlyClaire Aug 9, 2024
658addc
Add ability to report, block and mute from notification requests list…
ClearlyClaire Aug 9, 2024
31a00c0
Merge commit '658addcbf783f6baa922d11c9524ebb9ddbcbc59' into glitch-s…
ClearlyClaire Aug 9, 2024
cc2949b
[Glitch] Fix styling issues with notification settings and mobile bor…
vmstan Aug 8, 2024
e7be55f
[Glitch] Fix list creation textbox styling
vmstan Aug 8, 2024
5a9f526
[Glitch] Update notification labels for mentions
renchap Aug 8, 2024
ce9715d
[Glitch] Change unread notification count to only cover the selected …
ClearlyClaire Aug 8, 2024
99d3816
[Glitch] Fix post filter & report styling
vmstan Aug 9, 2024
58b9b80
[Glitch] Add option to ignore filtered notifications to the web inter…
ClearlyClaire Aug 9, 2024
b6961d0
[Glitch] Add ability to report, block and mute from notification requ…
ClearlyClaire Aug 9, 2024
bcec8f5
Add hint to user that other remote statuses may not be displayed (#26…
audiodude Aug 9, 2024
28411ac
Fix “Accept all”/“Dismiss all” notification requests not working (#31…
ClearlyClaire Aug 9, 2024
f43a484
Merge commit '28411acebb5626acf43b44a7b6c33ac783156f72' into glitch-s…
ClearlyClaire Aug 9, 2024
57a6307
[Glitch] Add hint to user that other remote statuses may not be displ…
audiodude Aug 9, 2024
082c71f
[Glitch] Fix “Accept all”/“Dismiss all” notification requests not wor…
ClearlyClaire Aug 9, 2024
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
4 changes: 2 additions & 2 deletions app/controllers/api/v1/notifications/policies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ class Api::V1::Notifications::PoliciesController < Api::BaseController
before_action :set_policy

def show
render json: @policy, serializer: REST::NotificationPolicySerializer
render json: @policy, serializer: REST::V1::NotificationPolicySerializer
end

def update
@policy.update!(resource_params)
render json: @policy, serializer: REST::NotificationPolicySerializer
render json: @policy, serializer: REST::V1::NotificationPolicySerializer
end

private
Expand Down
38 changes: 38 additions & 0 deletions app/controllers/api/v2/notifications/policies_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

class Api::V2::Notifications::PoliciesController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, only: :show
before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: :update

before_action :require_user!
before_action :set_policy

def show
render json: @policy, serializer: REST::NotificationPolicySerializer
end

def update
@policy.update!(resource_params)
render json: @policy, serializer: REST::NotificationPolicySerializer
end

private

def set_policy
@policy = NotificationPolicy.find_or_initialize_by(account: current_account)

with_read_replica do
@policy.summarize!
end
end

def resource_params
params.permit(
:for_not_following,
:for_not_followers,
:for_new_accounts,
:for_private_mentions,
:for_limited_accounts
)
end
end
64 changes: 64 additions & 0 deletions app/javascript/flavours/glitch/actions/notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ export const NOTIFICATION_REQUEST_DISMISS_REQUEST = 'NOTIFICATION_REQUEST_DISMIS
export const NOTIFICATION_REQUEST_DISMISS_SUCCESS = 'NOTIFICATION_REQUEST_DISMISS_SUCCESS';
export const NOTIFICATION_REQUEST_DISMISS_FAIL = 'NOTIFICATION_REQUEST_DISMISS_FAIL';

export const NOTIFICATION_REQUESTS_ACCEPT_REQUEST = 'NOTIFICATION_REQUESTS_ACCEPT_REQUEST';
export const NOTIFICATION_REQUESTS_ACCEPT_SUCCESS = 'NOTIFICATION_REQUESTS_ACCEPT_SUCCESS';
export const NOTIFICATION_REQUESTS_ACCEPT_FAIL = 'NOTIFICATION_REQUESTS_ACCEPT_FAIL';

export const NOTIFICATION_REQUESTS_DISMISS_REQUEST = 'NOTIFICATION_REQUESTS_DISMISS_REQUEST';
export const NOTIFICATION_REQUESTS_DISMISS_SUCCESS = 'NOTIFICATION_REQUESTS_DISMISS_SUCCESS';
export const NOTIFICATION_REQUESTS_DISMISS_FAIL = 'NOTIFICATION_REQUESTS_DISMISS_FAIL';

export const NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST = 'NOTIFICATIONS_FOR_REQUEST_FETCH_REQUEST';
export const NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS = 'NOTIFICATIONS_FOR_REQUEST_FETCH_SUCCESS';
export const NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL = 'NOTIFICATIONS_FOR_REQUEST_FETCH_FAIL';
Expand Down Expand Up @@ -584,6 +592,62 @@ export const dismissNotificationRequestFail = (id, error) => ({
error,
});

export const acceptNotificationRequests = (ids) => (dispatch, getState) => {
const count = ids.reduce((count, id) => count + selectNotificationCountForRequest(getState(), id), 0);
dispatch(acceptNotificationRequestsRequest(ids));

api().post(`/api/v1/notifications/requests/accept`, { id: ids }).then(() => {
dispatch(acceptNotificationRequestsSuccess(ids));
dispatch(decreasePendingNotificationsCount(count));
}).catch(err => {
dispatch(acceptNotificationRequestFail(ids, err));
});
};

export const acceptNotificationRequestsRequest = ids => ({
type: NOTIFICATION_REQUESTS_ACCEPT_REQUEST,
ids,
});

export const acceptNotificationRequestsSuccess = ids => ({
type: NOTIFICATION_REQUESTS_ACCEPT_SUCCESS,
ids,
});

export const acceptNotificationRequestsFail = (ids, error) => ({
type: NOTIFICATION_REQUESTS_ACCEPT_FAIL,
ids,
error,
});

export const dismissNotificationRequests = (ids) => (dispatch, getState) => {
const count = ids.reduce((count, id) => count + selectNotificationCountForRequest(getState(), id), 0);
dispatch(acceptNotificationRequestsRequest(ids));

api().post(`/api/v1/notifications/requests/dismiss`, { id: ids }).then(() => {
dispatch(dismissNotificationRequestsSuccess(ids));
dispatch(decreasePendingNotificationsCount(count));
}).catch(err => {
dispatch(dismissNotificationRequestFail(ids, err));
});
};

export const dismissNotificationRequestsRequest = ids => ({
type: NOTIFICATION_REQUESTS_DISMISS_REQUEST,
ids,
});

export const dismissNotificationRequestsSuccess = ids => ({
type: NOTIFICATION_REQUESTS_DISMISS_SUCCESS,
ids,
});

export const dismissNotificationRequestsFail = (ids, error) => ({
type: NOTIFICATION_REQUESTS_DISMISS_FAIL,
ids,
error,
});

export const fetchNotificationsForRequest = accountId => (dispatch, getState) => {
const current = getState().getIn(['notificationRequests', 'current']);
const params = { account_id: accountId };
Expand Down
4 changes: 2 additions & 2 deletions app/javascript/flavours/glitch/api/notification_policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { apiRequestGet, apiRequestPut } from 'flavours/glitch/api';
import type { NotificationPolicyJSON } from 'flavours/glitch/api_types/notification_policies';

export const apiGetNotificationPolicy = () =>
apiRequestGet<NotificationPolicyJSON>('/v1/notifications/policy');
apiRequestGet<NotificationPolicyJSON>('/v2/notifications/policy');

export const apiUpdateNotificationsPolicy = (
policy: Partial<NotificationPolicyJSON>,
) => apiRequestPut<NotificationPolicyJSON>('/v1/notifications/policy', policy);
) => apiRequestPut<NotificationPolicyJSON>('/v2/notifications/policy', policy);
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// See app/serializers/rest/notification_policy_serializer.rb

export type NotificationPolicyValue = 'accept' | 'filter' | 'drop';

export interface NotificationPolicyJSON {
filter_not_following: boolean;
filter_not_followers: boolean;
filter_new_accounts: boolean;
filter_private_mentions: boolean;
for_not_following: NotificationPolicyValue;
for_not_followers: NotificationPolicyValue;
for_new_accounts: NotificationPolicyValue;
for_private_mentions: NotificationPolicyValue;
for_limited_accounts: NotificationPolicyValue;
summary: {
pending_requests_count: number;
pending_notifications_count: number;
Expand Down
13 changes: 11 additions & 2 deletions app/javascript/flavours/glitch/components/check_box.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import classNames from 'classnames';

import CheckIndeterminateSmallIcon from '@/material-icons/400-24px/check_indeterminate_small.svg?react';
import DoneIcon from '@/material-icons/400-24px/done.svg?react';

import { Icon } from './icon';

interface Props {
value: string;
checked: boolean;
indeterminate: boolean;
name: string;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
label: React.ReactNode;
Expand All @@ -16,6 +18,7 @@ export const CheckBox: React.FC<Props> = ({
name,
value,
checked,
indeterminate,
onChange,
label,
}) => {
Expand All @@ -29,8 +32,14 @@ export const CheckBox: React.FC<Props> = ({
onChange={onChange}
/>

<span className={classNames('check-box__input', { checked })}>
{checked && <Icon id='check' icon={DoneIcon} />}
<span
className={classNames('check-box__input', { checked, indeterminate })}
>
{indeterminate ? (
<Icon id='indeterminate' icon={CheckIndeterminateSmallIcon} />
) : (
checked && <Icon id='check' icon={DoneIcon} />
)}
</span>

<span>{label}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const listenerOptions = supportsPassiveEvents
? { passive: true, capture: true }
: true;

interface SelectItem {
export interface SelectItem {
value: string;
icon?: string;
iconComponent?: IconProp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@ import { useCallback } from 'react';

import { defineMessages, useIntl } from 'react-intl';

import { Link } from 'react-router-dom';
import classNames from 'classnames';
import { Link, useHistory } from 'react-router-dom';

import { useSelector, useDispatch } from 'react-redux';

import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
import DoneIcon from '@/material-icons/400-24px/done.svg?react';
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
import { initBlockModal } from 'flavours/glitch/actions/blocks';
import { initMuteModal } from 'flavours/glitch/actions/mutes';
import { acceptNotificationRequest, dismissNotificationRequest } from 'flavours/glitch/actions/notifications';
import { initReport } from 'flavours/glitch/actions/reports';
import { Avatar } from 'flavours/glitch/components/avatar';
import { CheckBox } from 'flavours/glitch/components/check_box';
import { IconButton } from 'flavours/glitch/components/icon_button';
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
import { makeGetAccount } from 'flavours/glitch/selectors';
import { toCappedNumber } from 'flavours/glitch/utils/numbers';

Expand All @@ -20,12 +26,18 @@ const getAccount = makeGetAccount();
const messages = defineMessages({
accept: { id: 'notification_requests.accept', defaultMessage: 'Accept' },
dismiss: { id: 'notification_requests.dismiss', defaultMessage: 'Dismiss' },
view: { id: 'notification_requests.view', defaultMessage: 'View notifications' },
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
report: { id: 'status.report', defaultMessage: 'Report @{name}' },
more: { id: 'status.more', defaultMessage: 'More' },
});

export const NotificationRequest = ({ id, accountId, notificationsCount }) => {
export const NotificationRequest = ({ id, accountId, notificationsCount, checked, showCheckbox, toggleCheck }) => {
const dispatch = useDispatch();
const account = useSelector(state => getAccount(state, accountId));
const intl = useIntl();
const { push: historyPush } = useHistory();

const handleDismiss = useCallback(() => {
dispatch(dismissNotificationRequest(id));
Expand All @@ -35,9 +47,51 @@ export const NotificationRequest = ({ id, accountId, notificationsCount }) => {
dispatch(acceptNotificationRequest(id));
}, [dispatch, id]);

const handleMute = useCallback(() => {
dispatch(initMuteModal(account));
}, [dispatch, account]);

const handleBlock = useCallback(() => {
dispatch(initBlockModal(account));
}, [dispatch, account]);

const handleReport = useCallback(() => {
dispatch(initReport(account));
}, [dispatch, account]);

const handleView = useCallback(() => {
historyPush(`/notifications/requests/${id}`);
}, [historyPush, id]);

const menu = [
{ text: intl.formatMessage(messages.view), action: handleView },
null,
{ text: intl.formatMessage(messages.accept), action: handleAccept },
null,
{ text: intl.formatMessage(messages.mute, { name: account.username }), action: handleMute, dangerous: true },
{ text: intl.formatMessage(messages.block, { name: account.username }), action: handleBlock, dangerous: true },
{ text: intl.formatMessage(messages.report, { name: account.username }), action: handleReport, dangerous: true },
];

const handleCheck = useCallback(() => {
toggleCheck(id);
}, [toggleCheck, id]);

const handleClick = useCallback((e) => {
if (showCheckbox) {
toggleCheck(id);
e.preventDefault();
e.stopPropagation();
}
}, [toggleCheck, id, showCheckbox]);

return (
<div className='notification-request'>
<Link to={`/notifications/requests/${id}`} className='notification-request__link'>
/* eslint-disable-next-line jsx-a11y/no-static-element-interactions -- this is just a minor affordance, but we will need a comprehensive accessibility pass */
<div className={classNames('notification-request', showCheckbox && 'notification-request--forced-checkbox')} onClick={handleClick}>
<div className='notification-request__checkbox' aria-hidden={!showCheckbox}>
<CheckBox checked={checked} onChange={handleCheck} />
</div>
<Link to={`/notifications/requests/${id}`} className='notification-request__link' onClick={handleClick} title={account?.acct}>
<Avatar account={account} size={40} counter={toCappedNumber(notificationsCount)} />

<div className='notification-request__name'>
Expand All @@ -51,7 +105,13 @@ export const NotificationRequest = ({ id, accountId, notificationsCount }) => {

<div className='notification-request__actions'>
<IconButton iconComponent={DeleteIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
<IconButton iconComponent={DoneIcon} onClick={handleAccept} title={intl.formatMessage(messages.accept)} />
<DropdownMenuContainer
items={menu}
icons='ellipsis-h'
iconComponent={MoreHorizIcon}
direction='right'
title={intl.formatMessage(messages.more)}
/>
</div>
</div>
);
Expand All @@ -61,4 +121,7 @@ NotificationRequest.propTypes = {
id: PropTypes.string.isRequired,
accountId: PropTypes.string.isRequired,
notificationsCount: PropTypes.string.isRequired,
checked: PropTypes.bool,
showCheckbox: PropTypes.bool,
toggleCheck: PropTypes.func,
};
Loading