Merge commit 'c4eec632b92c800ae38dba111c4c76e63bb1c0de' into glitch-soc/merge-upstream
This commit is contained in:
commit
b6abf7a69f
@ -76,6 +76,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.emptyMessage {
|
.emptyMessage {
|
||||||
padding: 8px 16px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 16px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loadingIndicator {
|
||||||
|
--spinner-size: 20px;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: var(--spinner-size);
|
||||||
|
height: var(--spinner-size);
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
& :global(.circular-progress) {
|
||||||
|
width: var(--spinner-size);
|
||||||
|
height: var(--spinner-size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -22,6 +22,8 @@ import { matchWidth } from 'mastodon/components/dropdown/utils';
|
|||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
import { useOnClickOutside } from 'mastodon/hooks/useOnClickOutside';
|
import { useOnClickOutside } from 'mastodon/hooks/useOnClickOutside';
|
||||||
|
|
||||||
|
import { LoadingIndicator } from '../loading_indicator';
|
||||||
|
|
||||||
import classes from './combobox.module.scss';
|
import classes from './combobox.module.scss';
|
||||||
import { FormFieldWrapper } from './form_field_wrapper';
|
import { FormFieldWrapper } from './form_field_wrapper';
|
||||||
import type { CommonFieldWrapperProps } from './form_field_wrapper';
|
import type { CommonFieldWrapperProps } from './form_field_wrapper';
|
||||||
@ -531,6 +533,7 @@ const ComboboxWithRef = <Item extends ComboboxItem, GroupKey extends string>(
|
|||||||
<div {...props} className={classNames(classes.popover, placement)}>
|
<div {...props} className={classNames(classes.popover, placement)}>
|
||||||
<StatusMessageWrapper
|
<StatusMessageWrapper
|
||||||
showStatus={showStatusMessageInMenu}
|
showStatus={showStatusMessageInMenu}
|
||||||
|
isLoading={isLoading}
|
||||||
status={statusMessage}
|
status={statusMessage}
|
||||||
>
|
>
|
||||||
{hasGroups ? (
|
{hasGroups ? (
|
||||||
@ -592,10 +595,20 @@ Combobox.displayName = 'Combobox';
|
|||||||
const StatusMessageWrapper: React.FC<{
|
const StatusMessageWrapper: React.FC<{
|
||||||
showStatus: boolean;
|
showStatus: boolean;
|
||||||
status: string;
|
status: string;
|
||||||
|
isLoading: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}> = ({ showStatus, status, children }) => {
|
}> = ({ showStatus, status, isLoading, children }) => {
|
||||||
if (showStatus) {
|
if (showStatus) {
|
||||||
return <span className={classes.emptyMessage}>{status}</span>;
|
return (
|
||||||
|
<span className={classes.emptyMessage}>
|
||||||
|
{isLoading && (
|
||||||
|
<span className={classes.loadingIndicator}>
|
||||||
|
<LoadingIndicator role='none' />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{status}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return children;
|
return children;
|
||||||
|
|||||||
@ -1,3 +1,13 @@
|
|||||||
|
.wrapper {
|
||||||
|
--diameter: 20px;
|
||||||
|
--padding: 2px;
|
||||||
|
--transition: 0.2s ease-in-out;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
height: calc(var(--diameter) + var(--padding) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@ -9,10 +19,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.toggle {
|
.toggle {
|
||||||
--diameter: 20px;
|
|
||||||
--padding: 2px;
|
|
||||||
--transition: 0.2s ease-in-out;
|
|
||||||
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
@ -68,8 +74,3 @@
|
|||||||
:global([dir='rtl']) .input:checked + .toggle::before {
|
:global([dir='rtl']) .input:checked + .toggle::before {
|
||||||
transform: translateX(calc(-1 * (var(--diameter) - (var(--padding) * 2))));
|
transform: translateX(calc(-1 * (var(--diameter) - (var(--padding) * 2))));
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -31,20 +31,17 @@ ToggleField.displayName = 'ToggleField';
|
|||||||
|
|
||||||
export const Toggle = forwardRef<HTMLInputElement, Props>(
|
export const Toggle = forwardRef<HTMLInputElement, Props>(
|
||||||
({ className, size, ...otherProps }, ref) => (
|
({ className, size, ...otherProps }, ref) => (
|
||||||
<span className={classes.wrapper}>
|
<span
|
||||||
|
className={classes.wrapper}
|
||||||
|
style={{ '--diameter': size ? `${size}px` : undefined } as CSSProperties}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
type='checkbox'
|
type='checkbox'
|
||||||
className={classes.input}
|
className={classes.input}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
/>
|
/>
|
||||||
<span
|
<span className={classNames(classes.toggle, className)} hidden />
|
||||||
className={classNames(classes.toggle, className)}
|
|
||||||
style={
|
|
||||||
{ '--diameter': size ? `${size}px` : undefined } as CSSProperties
|
|
||||||
}
|
|
||||||
hidden
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -331,6 +331,10 @@ const TopicField: React.FC = () => {
|
|||||||
[topic],
|
[topic],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isCurrentTopicOnlySuggestion =
|
||||||
|
tags.length === 1 && tags[0]?.id === 'new';
|
||||||
|
const hideTagSuggestions = !tags.length || isCurrentTopicOnlySuggestion;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ComboboxField
|
<ComboboxField
|
||||||
required={false}
|
required={false}
|
||||||
@ -369,7 +373,7 @@ const TopicField: React.FC = () => {
|
|||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
suppressMenu={!tags.length}
|
suppressMenu={hideTagSuggestions}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,8 +7,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||||||
|
|
||||||
import { NonceProvider } from 'react-select';
|
import { NonceProvider } from 'react-select';
|
||||||
import AsyncSelect from 'react-select/async';
|
import AsyncSelect from 'react-select/async';
|
||||||
import Toggle from 'react-toggle';
|
|
||||||
|
|
||||||
|
import { Toggle } from '@/mastodon/components/form_fields/toggle_field';
|
||||||
import { injectIntl } from '@/mastodon/components/intl';
|
import { injectIntl } from '@/mastodon/components/intl';
|
||||||
|
|
||||||
import SettingToggle from '../../notifications/components/setting_toggle';
|
import SettingToggle from '../../notifications/components/setting_toggle';
|
||||||
|
|||||||
@ -7,8 +7,6 @@ import { useParams, useHistory, Link } from 'react-router-dom';
|
|||||||
|
|
||||||
import { isFulfilled } from '@reduxjs/toolkit';
|
import { isFulfilled } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import Toggle from 'react-toggle';
|
|
||||||
|
|
||||||
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
|
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
|
||||||
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
|
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
|
||||||
import { fetchList } from 'mastodon/actions/lists';
|
import { fetchList } from 'mastodon/actions/lists';
|
||||||
@ -20,7 +18,11 @@ import { Avatar } from 'mastodon/components/avatar';
|
|||||||
import { AvatarGroup } from 'mastodon/components/avatar_group';
|
import { AvatarGroup } from 'mastodon/components/avatar_group';
|
||||||
import { Column } from 'mastodon/components/column';
|
import { Column } from 'mastodon/components/column';
|
||||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||||
import { SelectField, TextInputField } from 'mastodon/components/form_fields';
|
import {
|
||||||
|
SelectField,
|
||||||
|
TextInputField,
|
||||||
|
Toggle,
|
||||||
|
} from 'mastodon/components/form_fields';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import type { List } from 'mastodon/models/list';
|
import type { List } from 'mastodon/models/list';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import type { PropsWithChildren } from 'react';
|
import type { PropsWithChildren } from 'react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import Toggle from 'react-toggle';
|
import { Toggle } from '@/mastodon/components/form_fields/toggle_field';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { PureComponent } from 'react';
|
|||||||
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
|
||||||
import Toggle from 'react-toggle';
|
import { Toggle } from '@/mastodon/components/form_fields/toggle_field';
|
||||||
|
|
||||||
export default class SettingToggle extends PureComponent {
|
export default class SettingToggle extends PureComponent {
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ export default class SettingToggle extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='setting-toggle'>
|
<div className='setting-toggle'>
|
||||||
<Toggle disabled={disabled} id={id} checked={settings.getIn(settingPath, defaultValue)} onChange={this.onChange} onKeyDown={this.onKeyDown} />
|
<Toggle disabled={disabled} id={id} checked={settings.getIn(settingPath, defaultValue)} onChange={this.onChange} onKeyDown={this.onKeyDown} size={16} />
|
||||||
<label htmlFor={id} className='setting-toggle__label'>{label}</label>
|
<label htmlFor={id} className='setting-toggle__label'>{label}</label>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,8 +6,6 @@ import classNames from 'classnames';
|
|||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import Toggle from 'react-toggle';
|
|
||||||
|
|
||||||
import AddPhotoAlternateIcon from '@/material-icons/400-24px/add_photo_alternate.svg?react';
|
import AddPhotoAlternateIcon from '@/material-icons/400-24px/add_photo_alternate.svg?react';
|
||||||
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
||||||
import PersonIcon from '@/material-icons/400-24px/person.svg?react';
|
import PersonIcon from '@/material-icons/400-24px/person.svg?react';
|
||||||
@ -16,7 +14,11 @@ import { closeOnboarding } from 'mastodon/actions/onboarding';
|
|||||||
import { Button } from 'mastodon/components/button';
|
import { Button } from 'mastodon/components/button';
|
||||||
import { Column } from 'mastodon/components/column';
|
import { Column } from 'mastodon/components/column';
|
||||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||||
import { TextAreaField, TextInputField } from 'mastodon/components/form_fields';
|
import {
|
||||||
|
TextAreaField,
|
||||||
|
TextInputField,
|
||||||
|
Toggle,
|
||||||
|
} from 'mastodon/components/form_fields';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import { me } from 'mastodon/initial_state';
|
import { me } from 'mastodon/initial_state';
|
||||||
|
|||||||
@ -6,8 +6,7 @@ import type { Map } from 'immutable';
|
|||||||
import { OrderedSet } from 'immutable';
|
import { OrderedSet } from 'immutable';
|
||||||
import { shallowEqual } from 'react-redux';
|
import { shallowEqual } from 'react-redux';
|
||||||
|
|
||||||
import Toggle from 'react-toggle';
|
import { Toggle } from '@/mastodon/components/form_fields/toggle_field';
|
||||||
|
|
||||||
import { fetchAccount } from 'mastodon/actions/accounts';
|
import { fetchAccount } from 'mastodon/actions/accounts';
|
||||||
import { Button } from 'mastodon/components/button';
|
import { Button } from 'mastodon/components/button';
|
||||||
import type { Status } from 'mastodon/models/status';
|
import type { Status } from 'mastodon/models/status';
|
||||||
|
|||||||
@ -13,12 +13,12 @@
|
|||||||
"about.not_available": "Þessar upplýsingar hafa ekki verið gerðar aðgengilegar á þessum netþjóni.",
|
"about.not_available": "Þessar upplýsingar hafa ekki verið gerðar aðgengilegar á þessum netþjóni.",
|
||||||
"about.powered_by": "Dreifhýstur samskiptamiðill keyrður með {mastodon}",
|
"about.powered_by": "Dreifhýstur samskiptamiðill keyrður með {mastodon}",
|
||||||
"about.rules": "Reglur netþjónsins",
|
"about.rules": "Reglur netþjónsins",
|
||||||
"account.account_note_header": "Einkaminnispunktur",
|
"account.account_note_header": "Mínir minnispunktar",
|
||||||
"account.activity": "Virkni",
|
"account.activity": "Virkni",
|
||||||
"account.add_note": "Bæta við einkaminnispunkti",
|
"account.add_note": "Bæta við persónulegum minnispunkti",
|
||||||
"account.add_or_remove_from_list": "Bæta við eða fjarlægja af listum",
|
"account.add_or_remove_from_list": "Bæta við eða fjarlægja af listum",
|
||||||
"account.badges.admin": "Stjóri",
|
"account.badges.admin": "Stjóri",
|
||||||
"account.badges.blocked": "Lokað á",
|
"account.badges.blocked": "Útilokað",
|
||||||
"account.badges.bot": "Yrki",
|
"account.badges.bot": "Yrki",
|
||||||
"account.badges.domain_blocked": "Útilokað lén",
|
"account.badges.domain_blocked": "Útilokað lén",
|
||||||
"account.badges.group": "Hópur",
|
"account.badges.group": "Hópur",
|
||||||
@ -28,13 +28,13 @@
|
|||||||
"account.block_domain": "Útiloka lénið {domain}",
|
"account.block_domain": "Útiloka lénið {domain}",
|
||||||
"account.block_short": "Útiloka",
|
"account.block_short": "Útiloka",
|
||||||
"account.blocked": "Útilokaður",
|
"account.blocked": "Útilokaður",
|
||||||
"account.blocking": "Útilokun",
|
"account.blocking": "Útilokað",
|
||||||
"account.cancel_follow_request": "Taka fylgjendabeiðni til baka",
|
"account.cancel_follow_request": "Taka fylgjendabeiðni til baka",
|
||||||
"account.copy": "Afrita tengil í notandasnið",
|
"account.copy": "Afrita tengil í notandasnið",
|
||||||
"account.direct": "Einkaspjall við @{name}",
|
"account.direct": "Einkaspjall við @{name}",
|
||||||
"account.disable_notifications": "Hætta að láta mig vita þegar @{name} sendir inn",
|
"account.disable_notifications": "Hætta að láta mig vita þegar @{name} sendir inn",
|
||||||
"account.domain_blocking": "Útiloka lén",
|
"account.domain_blocking": "Útilokað lén",
|
||||||
"account.edit_note": "Breyta einkaminnispunkti",
|
"account.edit_note": "Breyta persónulegum minnispunkti",
|
||||||
"account.edit_profile": "Breyta notandasniði",
|
"account.edit_profile": "Breyta notandasniði",
|
||||||
"account.edit_profile_short": "Breyta",
|
"account.edit_profile_short": "Breyta",
|
||||||
"account.enable_notifications": "Láta mig vita þegar @{name} sendir inn",
|
"account.enable_notifications": "Láta mig vita þegar @{name} sendir inn",
|
||||||
@ -55,8 +55,8 @@
|
|||||||
"account.filters.replies_toggle": "Birta svör",
|
"account.filters.replies_toggle": "Birta svör",
|
||||||
"account.follow": "Fylgjast með",
|
"account.follow": "Fylgjast með",
|
||||||
"account.follow_back": "Fylgjast með til baka",
|
"account.follow_back": "Fylgjast með til baka",
|
||||||
"account.follow_back_short": "Fylgjast með til baka",
|
"account.follow_back_short": "Fylgja líka",
|
||||||
"account.follow_request": "Beiðni um að fylgjast með",
|
"account.follow_request": "Beiðni um að fylgja",
|
||||||
"account.follow_request_cancel": "Hætta við beiðni",
|
"account.follow_request_cancel": "Hætta við beiðni",
|
||||||
"account.follow_request_cancel_short": "Hætta við",
|
"account.follow_request_cancel_short": "Hætta við",
|
||||||
"account.follow_request_short": "Beiðni",
|
"account.follow_request_short": "Beiðni",
|
||||||
@ -90,7 +90,7 @@
|
|||||||
"account.menu.note.description": "Einungis sýnilegt þér",
|
"account.menu.note.description": "Einungis sýnilegt þér",
|
||||||
"account.menu.open_original_page": "Skoða á {domain}",
|
"account.menu.open_original_page": "Skoða á {domain}",
|
||||||
"account.menu.remove_follower": "Fjarlægja fylgjanda",
|
"account.menu.remove_follower": "Fjarlægja fylgjanda",
|
||||||
"account.menu.report": "Kæra aðgang",
|
"account.menu.report": "Tilkynna aðgang",
|
||||||
"account.menu.share": "Deila…",
|
"account.menu.share": "Deila…",
|
||||||
"account.menu.show_reblogs": "Sýna endurbirtingar í tímalínu",
|
"account.menu.show_reblogs": "Sýna endurbirtingar í tímalínu",
|
||||||
"account.menu.unblock": "Aflétta útilokun aðgangs",
|
"account.menu.unblock": "Aflétta útilokun aðgangs",
|
||||||
@ -102,7 +102,7 @@
|
|||||||
"account.mute_short": "Þagga niður",
|
"account.mute_short": "Þagga niður",
|
||||||
"account.muted": "Þaggaður",
|
"account.muted": "Þaggaður",
|
||||||
"account.muting": "Þöggun",
|
"account.muting": "Þöggun",
|
||||||
"account.mutual": "Þið fylgist með hvor öðrum",
|
"account.mutual": "Þið fylgið hvor öðrum",
|
||||||
"account.name.copy": "Afrita kennislóð",
|
"account.name.copy": "Afrita kennislóð",
|
||||||
"account.name.help.domain": "{domain} er netþjónninn sem hýsir upplýsingasnið um notandann og færslurnar hans.",
|
"account.name.help.domain": "{domain} er netþjónninn sem hýsir upplýsingasnið um notandann og færslurnar hans.",
|
||||||
"account.name.help.domain_self": "{domain} er netþjónninn þinn sem hýsir upplýsingasniðið þitt og færslurnar þínar.",
|
"account.name.help.domain_self": "{domain} er netþjónninn þinn sem hýsir upplýsingasniðið þitt og færslurnar þínar.",
|
||||||
@ -125,7 +125,7 @@
|
|||||||
"account.remove_from_followers": "Fjarlægja {name} úr fylgjendum",
|
"account.remove_from_followers": "Fjarlægja {name} úr fylgjendum",
|
||||||
"account.report": "Kæra @{name}",
|
"account.report": "Kæra @{name}",
|
||||||
"account.requested_follow": "{name} hefur beðið um að fylgjast með þér",
|
"account.requested_follow": "{name} hefur beðið um að fylgjast með þér",
|
||||||
"account.requests_to_follow_you": "Bað um að fylgjast með þér",
|
"account.requests_to_follow_you": "Bað um að fylgja þér",
|
||||||
"account.share": "Deila notandasniði fyrir @{name}",
|
"account.share": "Deila notandasniði fyrir @{name}",
|
||||||
"account.show_reblogs": "Sýna endurbirtingar frá @{name}",
|
"account.show_reblogs": "Sýna endurbirtingar frá @{name}",
|
||||||
"account.statuses_counter": "{count, plural, one {{counter} færsla} other {{counter} færslur}}",
|
"account.statuses_counter": "{count, plural, one {{counter} færsla} other {{counter} færslur}}",
|
||||||
@ -402,7 +402,7 @@
|
|||||||
"collections.new_collection": "Nýtt safn",
|
"collections.new_collection": "Nýtt safn",
|
||||||
"collections.no_collections_yet": "Engin söfn ennþá.",
|
"collections.no_collections_yet": "Engin söfn ennþá.",
|
||||||
"collections.remove_account": "Fjarlægja",
|
"collections.remove_account": "Fjarlægja",
|
||||||
"collections.report_collection": "Kæra þetta safn",
|
"collections.report_collection": "Tilkynna þetta safn",
|
||||||
"collections.revoke_collection_inclusion": "Fjarlægja mig úr þessu safni",
|
"collections.revoke_collection_inclusion": "Fjarlægja mig úr þessu safni",
|
||||||
"collections.revoke_inclusion.confirmation": "Þú varst fjarlægð/ur úr \"{collection}\"",
|
"collections.revoke_inclusion.confirmation": "Þú varst fjarlægð/ur úr \"{collection}\"",
|
||||||
"collections.revoke_inclusion.error": "Upp kom villa, reyndu aftur síðar.",
|
"collections.revoke_inclusion.error": "Upp kom villa, reyndu aftur síðar.",
|
||||||
@ -412,8 +412,8 @@
|
|||||||
"collections.share_short": "Deila",
|
"collections.share_short": "Deila",
|
||||||
"collections.suggestions.can_not_add": "Er ekki hægt að bæta við",
|
"collections.suggestions.can_not_add": "Er ekki hægt að bæta við",
|
||||||
"collections.suggestions.can_not_add_desc": "Þessir aðgangar gætu hafa skráð sig úr almennri birtingu eða gætu verið á netþjónum sem ekki styðja söfn.",
|
"collections.suggestions.can_not_add_desc": "Þessir aðgangar gætu hafa skráð sig úr almennri birtingu eða gætu verið á netþjónum sem ekki styðja söfn.",
|
||||||
"collections.suggestions.must_follow": "Verður fyrst að fylgjast með",
|
"collections.suggestions.must_follow": "Verður fyrst að fylgja",
|
||||||
"collections.suggestions.must_follow_desc": "Þessir aðgangar yfirfara allar beiðnir um að fylgjast með. Fylgjendur geta bætt þeim í söfn.",
|
"collections.suggestions.must_follow_desc": "Þessir aðgangar yfirfara allar beiðnir um að fylgja þeim. Fylgjendur geta bætt þeim í söfn.",
|
||||||
"collections.topic_hint": "Bættu við myllumerki sem hjálpar öðrum að skilja aðalefni þessa safns.",
|
"collections.topic_hint": "Bættu við myllumerki sem hjálpar öðrum að skilja aðalefni þessa safns.",
|
||||||
"collections.topic_special_chars_hint": "Sérstafir verða fjarlægðir við vistun",
|
"collections.topic_special_chars_hint": "Sérstafir verða fjarlægðir við vistun",
|
||||||
"collections.unlisted_collections_description": "Þessi birtast ekki öðrum á notandasíðunni þinni. Þeir sem eru með tengil á þau geta séð þau.",
|
"collections.unlisted_collections_description": "Þessi birtast ekki öðrum á notandasíðunni þinni. Þeir sem eru með tengil á þau geta séð þau.",
|
||||||
@ -508,9 +508,9 @@
|
|||||||
"confirmations.discard_draft.post.title": "Henda drögum að færslunni þinni?",
|
"confirmations.discard_draft.post.title": "Henda drögum að færslunni þinni?",
|
||||||
"confirmations.discard_edit_media.confirm": "Henda",
|
"confirmations.discard_edit_media.confirm": "Henda",
|
||||||
"confirmations.discard_edit_media.message": "Þú ert með óvistaðar breytingar á lýsingu myndefnis eða forskoðunar, henda þeim samt?",
|
"confirmations.discard_edit_media.message": "Þú ert með óvistaðar breytingar á lýsingu myndefnis eða forskoðunar, henda þeim samt?",
|
||||||
"confirmations.follow_to_list.confirm": "Fylgjast með og bæta á lista",
|
"confirmations.follow_to_list.confirm": "Fylgja og bæta á lista",
|
||||||
"confirmations.follow_to_list.message": "Þú þarft að fylgjast með {name} til að bæta viðkomandi á lista.",
|
"confirmations.follow_to_list.message": "Þú þarft að fylgja {name} til að bæta viðkomandi á lista.",
|
||||||
"confirmations.follow_to_list.title": "Fylgjast með notanda?",
|
"confirmations.follow_to_list.title": "Fylgja notanda?",
|
||||||
"confirmations.hide_featured_tab.confirm": "Fela flipa",
|
"confirmations.hide_featured_tab.confirm": "Fela flipa",
|
||||||
"confirmations.hide_featured_tab.intro": "Þú getur breytt þessu hvenær sem er í <i>Breyta notandasniði > Stillingar notandasniðsflipa</i>.",
|
"confirmations.hide_featured_tab.intro": "Þú getur breytt þessu hvenær sem er í <i>Breyta notandasniði > Stillingar notandasniðsflipa</i>.",
|
||||||
"confirmations.hide_featured_tab.message": "Þetta mun fela flipann fyrir notendum á {serverName} og öðrum netþjónum sem nota nýjustu útgáfuna af Mastodon. Birting í öðrum viðmótum gæti verið á ýmsan máta.",
|
"confirmations.hide_featured_tab.message": "Þetta mun fela flipann fyrir notendum á {serverName} og öðrum netþjónum sem nota nýjustu útgáfuna af Mastodon. Birting í öðrum viðmótum gæti verið á ýmsan máta.",
|
||||||
@ -536,7 +536,7 @@
|
|||||||
"confirmations.redraft.message": "Ertu viss um að þú viljir eyða þessari færslu og enduvinna drögin? Eftirlæti og endurbirtingar munu glatast og svör við upprunalegu færslunni munu verða munaðarlaus.",
|
"confirmations.redraft.message": "Ertu viss um að þú viljir eyða þessari færslu og enduvinna drögin? Eftirlæti og endurbirtingar munu glatast og svör við upprunalegu færslunni munu verða munaðarlaus.",
|
||||||
"confirmations.redraft.title": "Eyða og byrja ný drög að færslu?",
|
"confirmations.redraft.title": "Eyða og byrja ný drög að færslu?",
|
||||||
"confirmations.remove_from_followers.confirm": "Fjarlægja fylgjanda",
|
"confirmations.remove_from_followers.confirm": "Fjarlægja fylgjanda",
|
||||||
"confirmations.remove_from_followers.message": "{name} mun hætta að fylgjast með þér. Ertu viss um að þú viljir halda áfram?",
|
"confirmations.remove_from_followers.message": "{name} mun hætta að fylgja þér. Ertu viss um að þú viljir halda áfram?",
|
||||||
"confirmations.remove_from_followers.title": "Fjarlægja fylgjanda?",
|
"confirmations.remove_from_followers.title": "Fjarlægja fylgjanda?",
|
||||||
"confirmations.revoke_collection_inclusion.confirm": "Fjarlægja mig",
|
"confirmations.revoke_collection_inclusion.confirm": "Fjarlægja mig",
|
||||||
"confirmations.revoke_collection_inclusion.message": "Þessi aðgerð er varanleg og umsjónaraðili safnsins mun ekki geta bætt þér aftur við síðar.",
|
"confirmations.revoke_collection_inclusion.message": "Þessi aðgerð er varanleg og umsjónaraðili safnsins mun ekki geta bætt þér aftur við síðar.",
|
||||||
@ -547,9 +547,9 @@
|
|||||||
"confirmations.unblock.confirm": "Aflétta útilokun",
|
"confirmations.unblock.confirm": "Aflétta útilokun",
|
||||||
"confirmations.unblock.title": "Aflétta útilokun á {name}?",
|
"confirmations.unblock.title": "Aflétta útilokun á {name}?",
|
||||||
"confirmations.unfollow.confirm": "Hætta að fylgja",
|
"confirmations.unfollow.confirm": "Hætta að fylgja",
|
||||||
"confirmations.unfollow.title": "Hætta að fylgjast með {name}?",
|
"confirmations.unfollow.title": "Hætta að fylgja {name}?",
|
||||||
"confirmations.withdraw_request.confirm": "Taka beiðni til baka",
|
"confirmations.withdraw_request.confirm": "Taka beiðni til baka",
|
||||||
"confirmations.withdraw_request.title": "Taka aftur beiðni um að fylgjast með {name}?",
|
"confirmations.withdraw_request.title": "Taka aftur beiðni um að fylgja {name}?",
|
||||||
"content_warning.hide": "Fela færslu",
|
"content_warning.hide": "Fela færslu",
|
||||||
"content_warning.show": "Birta samt",
|
"content_warning.show": "Birta samt",
|
||||||
"content_warning.show_more": "Sýna meira",
|
"content_warning.show_more": "Sýna meira",
|
||||||
@ -1113,7 +1113,7 @@
|
|||||||
"report.category.title_account": "notandasnið",
|
"report.category.title_account": "notandasnið",
|
||||||
"report.category.title_status": "færsla",
|
"report.category.title_status": "færsla",
|
||||||
"report.close": "Lokið",
|
"report.close": "Lokið",
|
||||||
"report.collection_comment": "Hvers vegna viltu kæra þetta safn?",
|
"report.collection_comment": "Afhverju viltu tilkynna þetta safn?",
|
||||||
"report.comment.title": "Er eitthvað annað sem þú heldur að við ættum að vita?",
|
"report.comment.title": "Er eitthvað annað sem þú heldur að við ættum að vita?",
|
||||||
"report.forward": "Áframsenda til {target}",
|
"report.forward": "Áframsenda til {target}",
|
||||||
"report.forward_hint": "Notandaaðgangurinn er af öðrum vefþjóni. Á einnig að senda nafnlaust afrit af kærunni þangað?",
|
"report.forward_hint": "Notandaaðgangurinn er af öðrum vefþjóni. Á einnig að senda nafnlaust afrit af kærunni þangað?",
|
||||||
|
|||||||
@ -410,6 +410,10 @@
|
|||||||
"collections.search_accounts_max_reached": "Du har lagt till maximalt antal konton",
|
"collections.search_accounts_max_reached": "Du har lagt till maximalt antal konton",
|
||||||
"collections.sensitive": "Känsligt",
|
"collections.sensitive": "Känsligt",
|
||||||
"collections.share_short": "Dela",
|
"collections.share_short": "Dela",
|
||||||
|
"collections.suggestions.can_not_add": "Kan inte läggas till",
|
||||||
|
"collections.suggestions.can_not_add_desc": "Dessa konton kan ha valt bort upptäckt, eller kan de vara på en server som inte stöder samlingar.",
|
||||||
|
"collections.suggestions.must_follow": "Måste följa först",
|
||||||
|
"collections.suggestions.must_follow_desc": "Dessa konton granskar alla följa förfrågningar. Följare kan lägga till dem i samlingar.",
|
||||||
"collections.topic_hint": "Lägg till en hashtagg som hjälper andra att förstå huvudämnet i denna samling.",
|
"collections.topic_hint": "Lägg till en hashtagg som hjälper andra att förstå huvudämnet i denna samling.",
|
||||||
"collections.topic_special_chars_hint": "Specialtecken kommer att tas bort när du sparar",
|
"collections.topic_special_chars_hint": "Specialtecken kommer att tas bort när du sparar",
|
||||||
"collections.unlisted_collections_description": "Dessa visas inte på din profil till andra. Vem som helst med länken kan upptäcka dem.",
|
"collections.unlisted_collections_description": "Dessa visas inte på din profil till andra. Vem som helst med länken kan upptäcka dem.",
|
||||||
|
|||||||
@ -1122,7 +1122,7 @@ a.name-tag,
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
&:hover {
|
&:where(a):where(:hover, :focus, :active) {
|
||||||
color: var(--color-text-brand);
|
color: var(--color-text-brand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1131,14 +1131,6 @@ a.name-tag,
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.announcements-list__item__title {
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__action-bar {
|
&__action-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@ -53,6 +53,7 @@ class Collection < ApplicationRecord
|
|||||||
validates :language, language: { if: :local?, allow_nil: true }
|
validates :language, language: { if: :local?, allow_nil: true }
|
||||||
validate :tag_is_usable
|
validate :tag_is_usable
|
||||||
validate :items_do_not_exceed_limit
|
validate :items_do_not_exceed_limit
|
||||||
|
validate :user_does_not_exceed_limit, on: :create
|
||||||
|
|
||||||
scope :with_items, -> { includes(:collection_items).merge(CollectionItem.with_accounts) }
|
scope :with_items, -> { includes(:collection_items).merge(CollectionItem.with_accounts) }
|
||||||
scope :with_tag, -> { includes(:tag) }
|
scope :with_tag, -> { includes(:tag) }
|
||||||
@ -105,4 +106,11 @@ class Collection < ApplicationRecord
|
|||||||
def items_do_not_exceed_limit
|
def items_do_not_exceed_limit
|
||||||
errors.add(:collection_items, :too_many, count: MAX_ITEMS) if pending_or_accepted_items.size > MAX_ITEMS
|
errors.add(:collection_items, :too_many, count: MAX_ITEMS) if pending_or_accepted_items.size > MAX_ITEMS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_does_not_exceed_limit
|
||||||
|
return unless local?
|
||||||
|
|
||||||
|
limit = account.user.role.collection_limit
|
||||||
|
errors.add(:base, :too_many, count: limit) if account.collections.count >= limit
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,15 +4,16 @@
|
|||||||
#
|
#
|
||||||
# Table name: user_roles
|
# Table name: user_roles
|
||||||
#
|
#
|
||||||
# id :bigint(8) not null, primary key
|
# id :bigint(8) not null, primary key
|
||||||
# color :string default(""), not null
|
# collection_limit :integer default(10), not null
|
||||||
# highlighted :boolean default(FALSE), not null
|
# color :string default(""), not null
|
||||||
# name :string default(""), not null
|
# highlighted :boolean default(FALSE), not null
|
||||||
# permissions :bigint(8) default(0), not null
|
# name :string default(""), not null
|
||||||
# position :integer default(0), not null
|
# permissions :bigint(8) default(0), not null
|
||||||
# require_2fa :boolean default(FALSE), not null
|
# position :integer default(0), not null
|
||||||
# created_at :datetime not null
|
# require_2fa :boolean default(FALSE), not null
|
||||||
# updated_at :datetime not null
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
#
|
#
|
||||||
|
|
||||||
class UserRole < ApplicationRecord
|
class UserRole < ApplicationRecord
|
||||||
@ -104,6 +105,7 @@ class UserRole < ApplicationRecord
|
|||||||
validates :name, presence: true, unless: :everyone?
|
validates :name, presence: true, unless: :everyone?
|
||||||
validates :color, format: { with: CSS_COLORS }, if: :color?
|
validates :color, format: { with: CSS_COLORS }, if: :color?
|
||||||
validates :position, numericality: { in: (-POSITION_LIMIT..POSITION_LIMIT) }
|
validates :position, numericality: { in: (-POSITION_LIMIT..POSITION_LIMIT) }
|
||||||
|
validates :collection_limit, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
||||||
|
|
||||||
validate :validate_permissions_elevation
|
validate :validate_permissions_elevation
|
||||||
validate :validate_position_elevation
|
validate :validate_position_elevation
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
class REST::RoleSerializer < ActiveModel::Serializer
|
class REST::RoleSerializer < ActiveModel::Serializer
|
||||||
attributes :id, :name, :permissions, :color, :highlighted
|
attributes :id, :name, :permissions, :color, :highlighted
|
||||||
|
|
||||||
|
attribute :collection_limit, if: -> { Mastodon::Feature.collections_enabled? }
|
||||||
|
|
||||||
def id
|
def id
|
||||||
object.id.to_s
|
object.id.to_s
|
||||||
end
|
end
|
||||||
|
|||||||
@ -32,6 +32,14 @@
|
|||||||
|
|
||||||
%hr.spacer/
|
%hr.spacer/
|
||||||
|
|
||||||
|
- if Mastodon::Feature.collections_enabled?
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= form.input :collection_limit,
|
||||||
|
wrapper: :with_label
|
||||||
|
|
||||||
|
%hr.spacer/
|
||||||
|
|
||||||
- unless current_user.role == form.object
|
- unless current_user.role == form.object
|
||||||
|
|
||||||
.field-group
|
.field-group
|
||||||
|
|||||||
@ -679,7 +679,7 @@ is:
|
|||||||
suspend_description_html: Notandaaðgangurinn og allt efni á honum mun verða óaðgengilegt og á endanum eytt út og samskipti við aðganginn verða ekki möguleg. Hægt að afturkalla innan 30 daga. Lokar öllum kærum gagnvart þessum aðgangi.
|
suspend_description_html: Notandaaðgangurinn og allt efni á honum mun verða óaðgengilegt og á endanum eytt út og samskipti við aðganginn verða ekki möguleg. Hægt að afturkalla innan 30 daga. Lokar öllum kærum gagnvart þessum aðgangi.
|
||||||
actions_description_html: Ákveddu til hvaða aðgerða eigi að taka til að leysa þessa kæru. Ef þú ákveður að refsa kærða notandaaðgangnum, verður viðkomandi send tilkynning í tölvupósti, nema ef flokkurinn <strong>Ruslpóstur</strong> sé valinn.
|
actions_description_html: Ákveddu til hvaða aðgerða eigi að taka til að leysa þessa kæru. Ef þú ákveður að refsa kærða notandaaðgangnum, verður viðkomandi send tilkynning í tölvupósti, nema ef flokkurinn <strong>Ruslpóstur</strong> sé valinn.
|
||||||
actions_description_remote_html: Ákveddu til hvaða aðgerða eigi að taka til að leysa þessa kæru. Þetta mun aðeins hafa áhrif á hvernig <strong>netþjónninn þinn</strong> meðhöndlar þennan fjartengda aðgang og efnið á honum.
|
actions_description_remote_html: Ákveddu til hvaða aðgerða eigi að taka til að leysa þessa kæru. Þetta mun aðeins hafa áhrif á hvernig <strong>netþjónninn þinn</strong> meðhöndlar þennan fjartengda aðgang og efnið á honum.
|
||||||
actions_no_posts: Þessi kæra er ekki með neinar tengdar færslur til að eyða
|
actions_no_posts: Þessi tilkynning er ekki með neinar tengdar færslur til að eyða
|
||||||
add_to_report: Bæta fleiru í kæru
|
add_to_report: Bæta fleiru í kæru
|
||||||
already_suspended_badges:
|
already_suspended_badges:
|
||||||
local: Þegar frystur á þessum netþjóni
|
local: Þegar frystur á þessum netþjóni
|
||||||
@ -884,7 +884,7 @@ is:
|
|||||||
public: Allir
|
public: Allir
|
||||||
landing_page:
|
landing_page:
|
||||||
values:
|
values:
|
||||||
about: Um hugbúnaðinn
|
about: Um
|
||||||
local_feed: Staðbundið streymi
|
local_feed: Staðbundið streymi
|
||||||
trends: Vinsælt
|
trends: Vinsælt
|
||||||
registrations:
|
registrations:
|
||||||
|
|||||||
@ -160,6 +160,7 @@ en:
|
|||||||
other: We have to make sure you're at least %{count} to use %{domain}. We won't store this.
|
other: We have to make sure you're at least %{count} to use %{domain}. We won't store this.
|
||||||
role: The role controls which permissions the user has.
|
role: The role controls which permissions the user has.
|
||||||
user_role:
|
user_role:
|
||||||
|
collection_limit: Limits the number of Collections that a single user with this role can create. Please note that when you decrease this number, users who are already at this limit will not lose any Collections. But they will not be able to create additional ones.
|
||||||
color: Color to be used for the role throughout the UI, as RGB in hex format
|
color: Color to be used for the role throughout the UI, as RGB in hex format
|
||||||
highlighted: This makes the role publicly visible
|
highlighted: This makes the role publicly visible
|
||||||
name: Public name of the role, if role is set to be displayed as a badge
|
name: Public name of the role, if role is set to be displayed as a badge
|
||||||
@ -386,6 +387,7 @@ en:
|
|||||||
role: Role
|
role: Role
|
||||||
time_zone: Time zone
|
time_zone: Time zone
|
||||||
user_role:
|
user_role:
|
||||||
|
collection_limit: Maximum number of Collections per user
|
||||||
color: Badge color
|
color: Badge color
|
||||||
highlighted: Display role as badge on user profiles
|
highlighted: Display role as badge on user profiles
|
||||||
name: Name
|
name: Name
|
||||||
|
|||||||
@ -61,6 +61,9 @@ sv:
|
|||||||
setting_default_quote_policy_private: Inlägg som endast är för följare och som författats på Mastodon kan inte citeras av andra.
|
setting_default_quote_policy_private: Inlägg som endast är för följare och som författats på Mastodon kan inte citeras av andra.
|
||||||
setting_default_quote_policy_unlisted: När folk citerar dig, kommer deras inlägg också att döljas från trendande tidslinjer.
|
setting_default_quote_policy_unlisted: När folk citerar dig, kommer deras inlägg också att döljas från trendande tidslinjer.
|
||||||
setting_default_sensitive: Känslig media döljs som standard och kan visas med ett klick
|
setting_default_sensitive: Känslig media döljs som standard och kan visas med ett klick
|
||||||
|
setting_display_media_default: Varna innan du visar media markerad som känslig
|
||||||
|
setting_display_media_hide_all: Varna innan du visar alla medier
|
||||||
|
setting_display_media_show_all: Visa alla medier utan varning, inklusive media markerad som känslig
|
||||||
setting_emoji_style: Hur emojier visas. "Automatiskt" kommer att försöka använda webbläsarens emojier, men faller tillbaka till Twemoji för äldre webbläsare.
|
setting_emoji_style: Hur emojier visas. "Automatiskt" kommer att försöka använda webbläsarens emojier, men faller tillbaka till Twemoji för äldre webbläsare.
|
||||||
setting_quick_boosting_html: När aktiverad, klicka på %{boost_icon} Boost-ikonen för att omedelbart boosta istället för att öppna boost/citera-rullgardinsmenyn. Flyttar citering till %{options_icon} (Alternativ)-menyn.
|
setting_quick_boosting_html: När aktiverad, klicka på %{boost_icon} Boost-ikonen för att omedelbart boosta istället för att öppna boost/citera-rullgardinsmenyn. Flyttar citering till %{options_icon} (Alternativ)-menyn.
|
||||||
setting_system_scrollbars_ui: Gäller endast för webbläsare som är baserade på Safari och Chrome
|
setting_system_scrollbars_ui: Gäller endast för webbläsare som är baserade på Safari och Chrome
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddCollectionLimitToUserRoles < ActiveRecord::Migration[8.1]
|
||||||
|
def change
|
||||||
|
add_column :user_roles, :collection_limit, :integer, null: false, default: 10
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -7,7 +7,7 @@ class MigrateRoles < ActiveRecord::Migration[5.2]
|
|||||||
class User < ApplicationRecord; end
|
class User < ApplicationRecord; end
|
||||||
|
|
||||||
def up
|
def up
|
||||||
load Rails.root.join('db', 'seeds', '03_roles.rb')
|
create_user_roles
|
||||||
|
|
||||||
owner_role = UserRole.find_by(name: 'Owner')
|
owner_role = UserRole.find_by(name: 'Owner')
|
||||||
moderator_role = UserRole.find_by(name: 'Moderator')
|
moderator_role = UserRole.find_by(name: 'Moderator')
|
||||||
@ -24,4 +24,30 @@ class MigrateRoles < ActiveRecord::Migration[5.2]
|
|||||||
User.where(role_id: [admin_role.id, owner_role.id]).in_batches.update_all(admin: true) if admin_role
|
User.where(role_id: [admin_role.id, owner_role.id]).in_batches.update_all(admin: true) if admin_role
|
||||||
User.where(role_id: moderator_role.id).in_batches.update_all(moderator: true) if moderator_role
|
User.where(role_id: moderator_role.id).in_batches.update_all(moderator: true) if moderator_role
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def create_user_roles
|
||||||
|
now = Time.zone.now.to_fs(:db)
|
||||||
|
|
||||||
|
safety_assured do
|
||||||
|
execute <<~SQL.squish
|
||||||
|
INSERT INTO user_roles ( id, permissions, created_at, updated_at )
|
||||||
|
VALUES ( -99, 65536, '#{now}', '#{now}' )
|
||||||
|
ON CONFLICT DO NOTHING
|
||||||
|
SQL
|
||||||
|
|
||||||
|
[
|
||||||
|
['Moderator', 10, 1308],
|
||||||
|
['Admin', 100, 983_036],
|
||||||
|
['Owner', 1000, 1],
|
||||||
|
].each do |name, position, permissions|
|
||||||
|
execute <<~SQL.squish
|
||||||
|
INSERT INTO user_roles ( name, position, highlighted, permissions, created_at, updated_at )
|
||||||
|
SELECT '#{name}', #{position}, true, #{permissions}, '#{now}', '#{now}'
|
||||||
|
WHERE NOT EXISTS ( SELECT 1 FROM user_roles WHERE name = '#{name}' )
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[8.1].define(version: 2026_04_15_133505) do
|
ActiveRecord::Schema[8.1].define(version: 2026_04_20_124030) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "pg_catalog.plpgsql"
|
enable_extension "pg_catalog.plpgsql"
|
||||||
|
|
||||||
@ -1340,6 +1340,7 @@ ActiveRecord::Schema[8.1].define(version: 2026_04_15_133505) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
create_table "user_roles", force: :cascade do |t|
|
create_table "user_roles", force: :cascade do |t|
|
||||||
|
t.integer "collection_limit", default: 10, null: false
|
||||||
t.string "color", default: "", null: false
|
t.string "color", default: "", null: false
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.boolean "highlighted", default: false, null: false
|
t.boolean "highlighted", default: false, null: false
|
||||||
|
|||||||
@ -107,7 +107,6 @@
|
|||||||
"react-select": "^5.7.3",
|
"react-select": "^5.7.3",
|
||||||
"react-sparklines": "^1.7.0",
|
"react-sparklines": "^1.7.0",
|
||||||
"react-textarea-autosize": "^8.4.1",
|
"react-textarea-autosize": "^8.4.1",
|
||||||
"react-toggle": "^4.1.3",
|
|
||||||
"redux-immutable": "^4.0.0",
|
"redux-immutable": "^4.0.0",
|
||||||
"regenerator-runtime": "^0.14.0",
|
"regenerator-runtime": "^0.14.0",
|
||||||
"requestidlecallback": "^0.3.0",
|
"requestidlecallback": "^0.3.0",
|
||||||
@ -160,7 +159,6 @@
|
|||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"@types/react-sparklines": "^1.7.2",
|
"@types/react-sparklines": "^1.7.2",
|
||||||
"@types/react-test-renderer": "^18.0.0",
|
"@types/react-test-renderer": "^18.0.0",
|
||||||
"@types/react-toggle": "^4.0.3",
|
|
||||||
"@types/redux-immutable": "^4.0.3",
|
"@types/redux-immutable": "^4.0.3",
|
||||||
"@types/requestidlecallback": "^0.3.5",
|
"@types/requestidlecallback": "^0.3.5",
|
||||||
"@vitest/browser": "^4.1.0",
|
"@vitest/browser": "^4.1.0",
|
||||||
|
|||||||
@ -71,6 +71,20 @@ RSpec.describe Collection do
|
|||||||
it { is_expected.to be_valid }
|
it { is_expected.to be_valid }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the user is already at the per-user limit of collections' do
|
||||||
|
subject { Fabricate.build(:collection, account:) }
|
||||||
|
|
||||||
|
let(:role) { Fabricate(:user_role, collection_limit: 2) }
|
||||||
|
let(:user) { Fabricate(:user, role:) }
|
||||||
|
let(:account) { user.account }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Fabricate.times(2, :collection, account:)
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to_not be_valid }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#item_for' do
|
describe '#item_for' do
|
||||||
|
|||||||
@ -31,6 +31,12 @@ RSpec.describe UserRole do
|
|||||||
it { is_expected.to_not allow_values('x', '112233445566', '#xxyyzz').for(:color) }
|
it { is_expected.to_not allow_values('x', '112233445566', '#xxyyzz').for(:color) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'collection_limit' do
|
||||||
|
subject { Fabricate.build :user_role }
|
||||||
|
|
||||||
|
it { is_expected.to validate_numericality_of(:collection_limit).only_integer.is_greater_than_or_equal_to(0) }
|
||||||
|
end
|
||||||
|
|
||||||
context 'when current_account is set' do
|
context 'when current_account is set' do
|
||||||
subject { Fabricate :user_role }
|
subject { Fabricate :user_role }
|
||||||
|
|
||||||
|
|||||||
43
spec/serializers/rest/role_serializer_spec.rb
Normal file
43
spec/serializers/rest/role_serializer_spec.rb
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe REST::RoleSerializer do
|
||||||
|
subject { serialized_record_json(role, described_class) }
|
||||||
|
|
||||||
|
let(:everyone) do
|
||||||
|
Fabricate.build(:user_role, permissions: 0)
|
||||||
|
end
|
||||||
|
let(:role) do
|
||||||
|
Fabricate.build(:user_role, id: 2342, name: 'test role', color: '#ABC', highlighted: true, permissions: 2300, collection_limit: 11)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(UserRole).to receive(:everyone).and_return(everyone)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'includes the relevant attributes' do
|
||||||
|
expect(subject)
|
||||||
|
.to include({
|
||||||
|
'id' => '2342',
|
||||||
|
'name' => 'test role',
|
||||||
|
'color' => '#ABC',
|
||||||
|
'highlighted' => true,
|
||||||
|
'permissions' => '2300',
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when collections are enabled', feature: :collections do
|
||||||
|
it 'includes the relevant attributes' do
|
||||||
|
expect(subject)
|
||||||
|
.to include({
|
||||||
|
'id' => '2342',
|
||||||
|
'name' => 'test role',
|
||||||
|
'color' => '#ABC',
|
||||||
|
'highlighted' => true,
|
||||||
|
'permissions' => '2300',
|
||||||
|
'collection_limit' => 11,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -6,6 +6,7 @@ import { optimizeLodashImports } from '@optimize-lodash/rollup-plugin';
|
|||||||
import babel from '@rolldown/plugin-babel';
|
import babel from '@rolldown/plugin-babel';
|
||||||
import legacy from '@vitejs/plugin-legacy';
|
import legacy from '@vitejs/plugin-legacy';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
|
import browserslist from 'browserslist';
|
||||||
import postcssPresetEnv from 'postcss-preset-env';
|
import postcssPresetEnv from 'postcss-preset-env';
|
||||||
import Compress from 'rollup-plugin-gzip';
|
import Compress from 'rollup-plugin-gzip';
|
||||||
import { visualizer } from 'rollup-plugin-visualizer';
|
import { visualizer } from 'rollup-plugin-visualizer';
|
||||||
@ -182,6 +183,7 @@ export const config: UserConfigFnPromise = async ({ mode, command }) => {
|
|||||||
legacy({
|
legacy({
|
||||||
renderLegacyChunks: false,
|
renderLegacyChunks: false,
|
||||||
modernPolyfills: true,
|
modernPolyfills: true,
|
||||||
|
modernTargets: browserslist.loadConfig({ path: process.cwd() }),
|
||||||
}),
|
}),
|
||||||
isProdBuild && (Compress() as PluginOption),
|
isProdBuild && (Compress() as PluginOption),
|
||||||
command === 'build' &&
|
command === 'build' &&
|
||||||
|
|||||||
40
yarn.lock
40
yarn.lock
@ -2885,7 +2885,6 @@ __metadata:
|
|||||||
"@types/react-router-dom": "npm:^5.3.3"
|
"@types/react-router-dom": "npm:^5.3.3"
|
||||||
"@types/react-sparklines": "npm:^1.7.2"
|
"@types/react-sparklines": "npm:^1.7.2"
|
||||||
"@types/react-test-renderer": "npm:^18.0.0"
|
"@types/react-test-renderer": "npm:^18.0.0"
|
||||||
"@types/react-toggle": "npm:^4.0.3"
|
|
||||||
"@types/redux-immutable": "npm:^4.0.3"
|
"@types/redux-immutable": "npm:^4.0.3"
|
||||||
"@types/requestidlecallback": "npm:^0.3.5"
|
"@types/requestidlecallback": "npm:^0.3.5"
|
||||||
"@use-gesture/react": "npm:^10.3.1"
|
"@use-gesture/react": "npm:^10.3.1"
|
||||||
@ -2966,7 +2965,6 @@ __metadata:
|
|||||||
react-sparklines: "npm:^1.7.0"
|
react-sparklines: "npm:^1.7.0"
|
||||||
react-test-renderer: "npm:^18.2.0"
|
react-test-renderer: "npm:^18.2.0"
|
||||||
react-textarea-autosize: "npm:^8.4.1"
|
react-textarea-autosize: "npm:^8.4.1"
|
||||||
react-toggle: "npm:^4.1.3"
|
|
||||||
redux-immutable: "npm:^4.0.0"
|
redux-immutable: "npm:^4.0.0"
|
||||||
regenerator-runtime: "npm:^0.14.0"
|
regenerator-runtime: "npm:^0.14.0"
|
||||||
requestidlecallback: "npm:^0.3.0"
|
requestidlecallback: "npm:^0.3.0"
|
||||||
@ -4791,15 +4789,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/react-toggle@npm:^4.0.3":
|
|
||||||
version: 4.0.5
|
|
||||||
resolution: "@types/react-toggle@npm:4.0.5"
|
|
||||||
dependencies:
|
|
||||||
"@types/react": "npm:*"
|
|
||||||
checksum: 10c0/f557b85c96715b145bcc3beb2903f88ee3a6045ef85da0f80561c7cc2ecdc531e2d4ae121ed8ec3a1761264de25b8410653744093f37abf042201587add7ffa6
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@types/react-transition-group@npm:^4.4.0":
|
"@types/react-transition-group@npm:^4.4.0":
|
||||||
version: 4.4.8
|
version: 4.4.8
|
||||||
resolution: "@types/react-transition-group@npm:4.4.8"
|
resolution: "@types/react-transition-group@npm:4.4.8"
|
||||||
@ -5927,11 +5916,11 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"baseline-browser-mapping@npm:^2.9.0":
|
"baseline-browser-mapping@npm:^2.9.0":
|
||||||
version: 2.9.2
|
version: 2.10.20
|
||||||
resolution: "baseline-browser-mapping@npm:2.9.2"
|
resolution: "baseline-browser-mapping@npm:2.10.20"
|
||||||
bin:
|
bin:
|
||||||
baseline-browser-mapping: dist/cli.js
|
baseline-browser-mapping: dist/cli.cjs
|
||||||
checksum: 10c0/4f9be09e20261ed26f19e9b95454dcb8d8371b87983c57cd9f70b9572e9b3053577f0d8d6d91297bdb605337747680686e22f62522a6e57ae2488fcacf641188
|
checksum: 10c0/3d60c9656c4c4673593aa8d0ae9aa6b69b4e018c2f585874a0e8a40cb28d0559f57ee1b2e7e44cb1e7f6aac66f658a4a3c1285901b8836d8ae31e189e30aa816
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -6160,9 +6149,9 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"caniuse-lite@npm:^1.0.30001759, caniuse-lite@npm:^1.0.30001766":
|
"caniuse-lite@npm:^1.0.30001759, caniuse-lite@npm:^1.0.30001766":
|
||||||
version: 1.0.30001770
|
version: 1.0.30001790
|
||||||
resolution: "caniuse-lite@npm:1.0.30001770"
|
resolution: "caniuse-lite@npm:1.0.30001790"
|
||||||
checksum: 10c0/02d15a8b723af65318cb4d888a52bb090076898da7b0de99e8676d537f8d1d2ae4797e81518e1e30cbfe84c33b048c322e8bfafc5b23cfee8defb0d2bf271149
|
checksum: 10c0/eec0adc1dcb35d51e57bcfa0657493cb57ef43f0ceb03c1edcfee34d43e7a938e6beed2781118c7a5ee99d4f71d443977f08ca5a549005cf89260733af9ad3f8
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -6245,7 +6234,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"classnames@npm:^2.2.5, classnames@npm:^2.3.2":
|
"classnames@npm:^2.3.2":
|
||||||
version: 2.5.1
|
version: 2.5.1
|
||||||
resolution: "classnames@npm:2.5.1"
|
resolution: "classnames@npm:2.5.1"
|
||||||
checksum: 10c0/afff4f77e62cea2d79c39962980bf316bacb0d7c49e13a21adaadb9221e1c6b9d3cdb829d8bb1b23c406f4e740507f37e1dcf506f7e3b7113d17c5bab787aa69
|
checksum: 10c0/afff4f77e62cea2d79c39962980bf316bacb0d7c49e13a21adaadb9221e1c6b9d3cdb829d8bb1b23c406f4e740507f37e1dcf506f7e3b7113d17c5bab787aa69
|
||||||
@ -12290,19 +12279,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"react-toggle@npm:^4.1.3":
|
|
||||||
version: 4.1.3
|
|
||||||
resolution: "react-toggle@npm:4.1.3"
|
|
||||||
dependencies:
|
|
||||||
classnames: "npm:^2.2.5"
|
|
||||||
peerDependencies:
|
|
||||||
prop-types: ">= 15.3.0 < 19"
|
|
||||||
react: ">= 15.3.0 < 19"
|
|
||||||
react-dom: ">= 15.3.0 < 19"
|
|
||||||
checksum: 10c0/afae643981d6fb922d66830ec0e9c793e729d7a55e3974edf212965acc8dc51f0d098ae6e409461d3ff2f87fe027dc3556a1a746f8472ed3a79c8878bf338fee
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"react-transition-group@npm:^4.3.0":
|
"react-transition-group@npm:^4.3.0":
|
||||||
version: 4.4.5
|
version: 4.4.5
|
||||||
resolution: "react-transition-group@npm:4.4.5"
|
resolution: "react-transition-group@npm:4.4.5"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user