[Glitch] Add notifications for statuses deleted by moderators
Port front-end changes from 14f436c457
to glitch-soc
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
remotes/1727458204337373841/tmp_refs/heads/signup-info-prompt
parent
b3bf32a21e
commit
69208ef6ff
|
@ -0,0 +1,159 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import api from 'flavours/glitch/util/api';
|
||||||
|
import { injectIntl, defineMessages } from 'react-intl';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
other: { id: 'report.categories.other', defaultMessage: 'Other' },
|
||||||
|
spam: { id: 'report.categories.spam', defaultMessage: 'Spam' },
|
||||||
|
violation: { id: 'report.categories.violation', defaultMessage: 'Content violates one or more server rules' },
|
||||||
|
});
|
||||||
|
|
||||||
|
class Category extends React.PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
text: PropTypes.string.isRequired,
|
||||||
|
selected: PropTypes.bool,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
onSelect: PropTypes.func,
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleClick = () => {
|
||||||
|
const { id, disabled, onSelect } = this.props;
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
onSelect(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { id, text, disabled, selected, children } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div tabIndex='0' role='button' className={classNames('report-reason-selector__category', { selected, disabled })} onClick={this.handleClick}>
|
||||||
|
{selected && <input type='hidden' name='report[category]' value={id} />}
|
||||||
|
|
||||||
|
<div className='report-reason-selector__category__label'>
|
||||||
|
<span className={classNames('poll__input', { active: selected, disabled })} />
|
||||||
|
{text}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{(selected && children) && (
|
||||||
|
<div className='report-reason-selector__category__rules'>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Rule extends React.PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
text: PropTypes.string.isRequired,
|
||||||
|
selected: PropTypes.bool,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
onToggle: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleClick = () => {
|
||||||
|
const { id, disabled, onToggle } = this.props;
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
onToggle(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { id, text, disabled, selected } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div tabIndex='0' role='button' className={classNames('report-reason-selector__rule', { selected, disabled })} onClick={this.handleClick}>
|
||||||
|
<span className={classNames('poll__input', { checkbox: true, active: selected, disabled })} />
|
||||||
|
{selected && <input type='hidden' name='report[rule_ids][]' value={id} />}
|
||||||
|
{text}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default @injectIntl
|
||||||
|
class ReportReasonSelector extends React.PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
category: PropTypes.string.isRequired,
|
||||||
|
rule_ids: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
category: this.props.category,
|
||||||
|
rule_ids: this.props.rule_ids || [],
|
||||||
|
rules: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
api().get('/api/v1/instance').then(res => {
|
||||||
|
this.setState({
|
||||||
|
rules: res.data.rules,
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_save = () => {
|
||||||
|
const { id, disabled } = this.props;
|
||||||
|
const { category, rule_ids } = this.state;
|
||||||
|
|
||||||
|
if (disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api().put(`/api/v1/admin/reports/${id}`, {
|
||||||
|
category,
|
||||||
|
rule_ids,
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSelect = id => {
|
||||||
|
this.setState({ category: id }, () => this._save());
|
||||||
|
};
|
||||||
|
|
||||||
|
handleToggle = id => {
|
||||||
|
const { rule_ids } = this.state;
|
||||||
|
|
||||||
|
if (rule_ids.includes(id)) {
|
||||||
|
this.setState({ rule_ids: rule_ids.filter(x => x !== id ) }, () => this._save());
|
||||||
|
} else {
|
||||||
|
this.setState({ rule_ids: [...rule_ids, id] }, () => this._save());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { disabled, intl } = this.props;
|
||||||
|
const { rules, category, rule_ids } = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='report-reason-selector'>
|
||||||
|
<Category id='other' text={intl.formatMessage(messages.other)} selected={category === 'other'} onSelect={this.handleSelect} disabled={disabled} />
|
||||||
|
<Category id='spam' text={intl.formatMessage(messages.spam)} selected={category === 'spam'} onSelect={this.handleSelect} disabled={disabled} />
|
||||||
|
<Category id='violation' text={intl.formatMessage(messages.violation)} selected={category === 'violation'} onSelect={this.handleSelect} disabled={disabled}>
|
||||||
|
{rules.map(rule => <Rule key={rule.id} id={rule.id} text={rule.text} selected={rule_ids.includes(rule.id)} onToggle={this.handleToggle} disabled={disabled} />)}
|
||||||
|
</Category>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -595,39 +595,44 @@ body,
|
||||||
|
|
||||||
.log-entry {
|
.log-entry {
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
padding: 15px 0;
|
padding: 15px;
|
||||||
|
padding-left: 15px * 2 + 40px;
|
||||||
background: $ui-base-color;
|
background: $ui-base-color;
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 4%);
|
border-bottom: 1px solid darken($ui-base-color, 8%);
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: lighten($ui-base-color, 4%);
|
||||||
|
}
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
color: $darker-text-color;
|
color: $darker-text-color;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 0 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__avatar {
|
&__avatar {
|
||||||
margin-right: 10px;
|
position: absolute;
|
||||||
|
left: 15px;
|
||||||
|
top: 15px;
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
display: block;
|
border-radius: 4px;
|
||||||
margin: 0;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__content {
|
|
||||||
max-width: calc(100% - 90px);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
&__title {
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
@ -643,6 +648,14 @@ body,
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a.name-tag,
|
a.name-tag,
|
||||||
|
@ -671,8 +684,9 @@ a.inline-name-tag,
|
||||||
|
|
||||||
a.name-tag,
|
a.name-tag,
|
||||||
.name-tag {
|
.name-tag {
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -1130,3 +1144,287 @@ a.sparkline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.report-reason-selector {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: $ui-base-color;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&__category {
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 1px solid darken($ui-base-color, 8%);
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__rules {
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__rule {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-header {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 15px;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 300px;
|
||||||
|
|
||||||
|
&__details {
|
||||||
|
&__item {
|
||||||
|
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
||||||
|
padding: 15px 0;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--horizontal {
|
||||||
|
display: grid;
|
||||||
|
grid-auto-columns: minmax(0, 1fr);
|
||||||
|
grid-auto-flow: column;
|
||||||
|
|
||||||
|
.report-header__details__item {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-card {
|
||||||
|
background: $ui-base-color;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
height: 128px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
background: darken($ui-base-color, 8%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
margin-top: -25px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
&__avatar {
|
||||||
|
padding: 15px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
background: darken($ui-base-color, 8%);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-name {
|
||||||
|
color: $darker-text-color;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
font-size: 15px;
|
||||||
|
|
||||||
|
bdi {
|
||||||
|
display: block;
|
||||||
|
color: $primary-text-color;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__bio {
|
||||||
|
padding: 0 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-wrap: break-word;
|
||||||
|
max-height: 18px * 2;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
width: 50px;
|
||||||
|
height: 18px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 15px;
|
||||||
|
background: linear-gradient(to left, $ui-base-color, transparent);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__counters {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: grid;
|
||||||
|
grid-auto-columns: minmax(0, 1fr);
|
||||||
|
grid-auto-flow: column;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
padding: 15px;
|
||||||
|
text-align: center;
|
||||||
|
color: $primary-text-color;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 15px;
|
||||||
|
|
||||||
|
small {
|
||||||
|
display: block;
|
||||||
|
color: $darker-text-color;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-notes {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
background: $ui-base-color;
|
||||||
|
position: relative;
|
||||||
|
padding: 15px;
|
||||||
|
padding-left: 15px * 2 + 40px;
|
||||||
|
border-bottom: 1px solid darken($ui-base-color, 8%);
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($ui-base-color, 4%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__avatar {
|
||||||
|
position: absolute;
|
||||||
|
left: 15px;
|
||||||
|
top: 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
color: $darker-text-color;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 20px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
|
||||||
|
.username a {
|
||||||
|
color: $primary-text-color;
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-right: 5px;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
time {
|
||||||
|
margin-left: 5px;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 20px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
font-weight: 400;
|
||||||
|
color: $primary-text-color;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
unicode-bidi: plaintext;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.report-actions {
|
||||||
|
border: 1px solid darken($ui-base-color, 8%);
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 18px;
|
||||||
|
border-bottom: 1px solid darken($ui-base-color, 8%);
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 100px;
|
||||||
|
padding: 15px;
|
||||||
|
padding-right: 0;
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $dark-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -150,6 +150,21 @@
|
||||||
&:active {
|
&:active {
|
||||||
outline: 0 !important;
|
outline: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
border-color: $dark-text-color;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: $dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
border-color: $dark-text-color;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__number {
|
&__number {
|
||||||
|
|
|
@ -3,7 +3,7 @@ export const profileLink = '/settings/profile';
|
||||||
export const signOutLink = '/auth/sign_out';
|
export const signOutLink = '/auth/sign_out';
|
||||||
export const termsLink = '/terms';
|
export const termsLink = '/terms';
|
||||||
export const accountAdminLink = (id) => `/admin/accounts/${id}`;
|
export const accountAdminLink = (id) => `/admin/accounts/${id}`;
|
||||||
export const statusAdminLink = (account_id, status_id) => `/admin/accounts/${account_id}/statuses/${status_id}`;
|
export const statusAdminLink = (account_id, status_id) => `/admin/accounts/${account_id}/statuses?id=${status_id}`;
|
||||||
export const filterEditLink = (id) => `/filters/${id}/edit`;
|
export const filterEditLink = (id) => `/filters/${id}/edit`;
|
||||||
export const relationshipsLink = '/relationships';
|
export const relationshipsLink = '/relationships';
|
||||||
export const securityLink = '/auth/edit';
|
export const securityLink = '/auth/edit';
|
||||||
|
|
Loading…
Reference in New Issue