diff --git a/Gemfile.lock b/Gemfile.lock
index e92684c50d..e8dbaad831 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -864,7 +864,7 @@ GEM
unicode-display_width (>= 1.1.1, < 4)
terrapin (1.1.1)
climate_control
- test-prof (1.6.0)
+ test-prof (1.6.1)
thor (1.5.0)
tilt (2.7.0)
timeout (0.6.1)
diff --git a/app/controllers/media_controller.rb b/app/controllers/media_controller.rb
index 0590ea4027..2aa83717c3 100644
--- a/app/controllers/media_controller.rb
+++ b/app/controllers/media_controller.rb
@@ -24,12 +24,7 @@ class MediaController < ApplicationController
private
def set_media_attachment
- id = params[:id] || params[:medium_id]
- return if id.nil?
-
- scope = MediaAttachment.local.attached
- # If id is 19 characters long, it's a shortcode, otherwise it's an identifier
- @media_attachment = id.size == 19 ? scope.find_by!(shortcode: id) : scope.find(id)
+ @media_attachment = MediaAttachment.local.attached.identified(params[:id])
end
def verify_permitted_status!
diff --git a/app/javascript/flavours/glitch/features/account_edit/components/tag_search.tsx b/app/javascript/flavours/glitch/features/account_edit/components/tag_search.tsx
index 7708012f94..cdc2602c08 100644
--- a/app/javascript/flavours/glitch/features/account_edit/components/tag_search.tsx
+++ b/app/javascript/flavours/glitch/features/account_edit/components/tag_search.tsx
@@ -65,7 +65,7 @@ export const AccountEditTagSearch: FC = () => {
value={query}
onChange={handleSearchChange}
placeholder={inputLabel}
- items={suggestedTags as TagSearchResult[]}
+ items={suggestedTags}
isLoading={isLoading}
renderItem={renderItem}
onSelectItem={handleSelect}
diff --git a/app/javascript/flavours/glitch/features/account_edit/index.tsx b/app/javascript/flavours/glitch/features/account_edit/index.tsx
index 41adaafcad..43cc86d4de 100644
--- a/app/javascript/flavours/glitch/features/account_edit/index.tsx
+++ b/app/javascript/flavours/glitch/features/account_edit/index.tsx
@@ -13,11 +13,15 @@ import { Button } from '@/flavours/glitch/components/button';
import { DismissibleCallout } from '@/flavours/glitch/components/callout/dismissible';
import { CustomEmojiProvider } from '@/flavours/glitch/components/emoji/context';
import { EmojiHTML } from '@/flavours/glitch/components/emoji/html';
+import { ToggleField } from '@/flavours/glitch/components/form_fields';
import { useElementHandledLink } from '@/flavours/glitch/components/status/handled_link';
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
import { autoPlayGif } from '@/flavours/glitch/initial_state';
-import { fetchProfile } from '@/flavours/glitch/reducers/slices/profile_edit';
+import {
+ fetchProfile,
+ patchProfile,
+} from '@/flavours/glitch/reducers/slices/profile_edit';
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
import { AccountEditColumn, AccountEditEmptyColumn } from './components/column';
@@ -108,6 +112,10 @@ export const messages = defineMessages({
id: 'account_edit.profile_tab.subtitle',
defaultMessage: 'Customize the tabs on your profile and what they display.',
},
+ advancedSettingsTitle: {
+ id: 'account_edit.advanced_settings.title',
+ defaultMessage: 'Advanced settings',
+ },
});
export const AccountEdit: FC = () => {
@@ -117,7 +125,7 @@ export const AccountEdit: FC = () => {
const dispatch = useAppDispatch();
- const { profile } = useAppSelector((state) => state.profileEdit);
+ const { profile, isPending } = useAppSelector((state) => state.profileEdit);
useEffect(() => {
void dispatch(fetchProfile());
}, [dispatch]);
@@ -162,6 +170,10 @@ export const AccountEdit: FC = () => {
history.push('/profile/featured_tags');
}, [history]);
+ const handleBotToggle = useCallback(() => {
+ void dispatch(patchProfile({ bot: !profile?.bot }));
+ }, [dispatch, profile?.bot]);
+
// Normally we would use the account emoji, but we want all custom emojis to be available to render after editing.
const emojis = useAppSelector((state) => state.custom_emojis);
const htmlHandlers = useElementHandledLink({
@@ -327,6 +339,26 @@ export const AccountEdit: FC = () => {
}
/>
+
+
+
+ }
+ hint={
+
+ }
+ />
+
);
diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/account_name.tsx b/app/javascript/flavours/glitch/features/account_timeline/components/account_name.tsx
index 5f0e173f58..5df7c8825b 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/components/account_name.tsx
+++ b/app/javascript/flavours/glitch/features/account_timeline/components/account_name.tsx
@@ -7,14 +7,17 @@ import classNames from 'classnames';
import Overlay from 'react-overlays/esm/Overlay';
+import { showAlert } from '@/flavours/glitch/actions/alerts';
import { Badge } from '@/flavours/glitch/components/badge';
+import { Button } from '@/flavours/glitch/components/button';
import { DisplayName } from '@/flavours/glitch/components/display_name';
import { Icon } from '@/flavours/glitch/components/icon';
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
import { useRelationship } from '@/flavours/glitch/hooks/useRelationship';
-import { useAppSelector } from '@/flavours/glitch/store';
+import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
import FollowerIcon from '@/images/icons/icon_follower.svg?react';
import AtIcon from '@/material-icons/400-24px/alternate_email.svg?react';
+import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react';
import HelpIcon from '@/material-icons/400-24px/help.svg?react';
import DomainIcon from '@/material-icons/400-24px/language.svg?react';
@@ -30,6 +33,10 @@ const messages = defineMessages({
id: 'account.name_info',
defaultMessage: 'What does this mean?',
},
+ copied: {
+ id: 'copy_icon_button.copied',
+ defaultMessage: 'Copied to clipboard',
+ },
});
export const AccountName: FC<{ accountId: string }> = ({ accountId }) => {
@@ -64,14 +71,12 @@ export const AccountName: FC<{ accountId: string }> = ({ accountId }) => {
/>
)}
-
- @{username}@{domain}
-
-
+
+
);
};
@@ -90,6 +95,19 @@ const AccountNameHelp: FC<{
setOpen((prev) => !prev);
}, []);
+ const handle = `@${username}@${domain}`;
+
+ const dispatch = useAppDispatch();
+ const [copied, setCopied] = useState(false);
+ const handleCopy = useCallback(() => {
+ void navigator.clipboard.writeText(handle);
+ setCopied(true);
+ dispatch(showAlert({ message: messages.copied }));
+ setTimeout(() => {
+ setCopied(false);
+ }, 700);
+ }, [handle, dispatch]);
+
return (
<>