diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 53b17e8cb2..be880e4457 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -6304,6 +6304,18 @@
"messageformat": "Choose who can send messages to the group.",
"description": "This is the additional info for the 'who can send messages' panel"
},
+ "icu:ConversationDetails--label-clear-warning--title": {
+ "messageformat": "Member labels will be cleared",
+ "description": "When the user changes the 'edit group info' permission to 'Admins only', this dialog shows. Title of dialog."
+ },
+ "icu:ConversationDetails--label-clear-warning--description": {
+ "messageformat": "Changing this permission to βOnly adminsβ will clear member labels set by non-admins in this group.",
+ "description": "When the user changes the 'edit group info' permission to 'Admins only', this dialog shows. Description text of dialog."
+ },
+ "icu:ConversationDetails--label-clear-warning--continue": {
+ "messageformat": "Continue",
+ "description": "When the user changes the 'edit group info' permission to 'Admins only', this dialog shows. Button to continue making the change."
+ },
"icu:ConversationDetails--requests-and-invites": {
"messageformat": "Requests & Invites",
"description": "This is a button to display which members have been invited but have not joined yet"
diff --git a/stylesheets/components/AboutContactModal.scss b/stylesheets/components/AboutContactModal.scss
index 5d37cc745d..5d4e3dae3d 100644
--- a/stylesheets/components/AboutContactModal.scss
+++ b/stylesheets/components/AboutContactModal.scss
@@ -125,6 +125,18 @@
display: flex;
align-items: center;
gap: 6px;
+
+ max-width: 100%;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ &__label-container__string {
+ min-width: 0px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
&__button {
diff --git a/ts/components/conversation/AboutContactModal.dom.stories.tsx b/ts/components/conversation/AboutContactModal.dom.stories.tsx
index 99ba52fc7a..d8d44d6452 100644
--- a/ts/components/conversation/AboutContactModal.dom.stories.tsx
+++ b/ts/components/conversation/AboutContactModal.dom.stories.tsx
@@ -103,6 +103,34 @@ export function MeWithLabel(args: PropsType): React.JSX.Element {
);
}
+export function LongLabel(args: PropsType): React.JSX.Element {
+ return (
+
+ );
+}
+
+export function LongLabelAllEmoji(args: PropsType): React.JSX.Element {
+ return (
+
+ );
+}
+
export function MeWithInvalidLabelEmoji(args: PropsType): React.JSX.Element {
return (
{' '}
>
@@ -316,7 +316,16 @@ export function AboutContactModal({
{labelEmojiElement}
- {contactLabelString}
+
+
+
)}
diff --git a/ts/components/conversation/conversation-details/GroupV2Permissions.dom.stories.tsx b/ts/components/conversation/conversation-details/GroupV2Permissions.dom.stories.tsx
index 0c4dffca21..c13439118b 100644
--- a/ts/components/conversation/conversation-details/GroupV2Permissions.dom.stories.tsx
+++ b/ts/components/conversation/conversation-details/GroupV2Permissions.dom.stories.tsx
@@ -8,6 +8,7 @@ import type { PropsType } from './GroupV2Permissions.dom.js';
import { GroupV2Permissions } from './GroupV2Permissions.dom.js';
import type { ConversationType } from '../../../state/ducks/conversations.preload.js';
import { getDefaultConversation } from '../../../test-helpers/getDefaultConversation.std.js';
+import { generateAci } from '../../../types/ServiceId.std.js';
const { i18n } = window.SignalContext;
@@ -15,11 +16,9 @@ export default {
title: 'Components/Conversation/ConversationDetails/GroupV2Permissions',
} satisfies Meta;
-const conversation: ConversationType = getDefaultConversation({
+const defaultConversation: ConversationType = getDefaultConversation({
id: '',
lastUpdated: 0,
- memberships: Array(32).fill({ member: getDefaultConversation({}) }),
- pendingMemberships: Array(16).fill({ member: getDefaultConversation({}) }),
title: 'Some Conversation',
type: 'group',
announcementsOnlyReady: true,
@@ -27,7 +26,7 @@ const conversation: ConversationType = getDefaultConversation({
});
const createProps = (): PropsType => ({
- conversation,
+ conversation: defaultConversation,
i18n,
setAccessControlAttributesSetting: action(
'setAccessControlAttributesSetting'
@@ -42,6 +41,64 @@ export function Basic(): React.JSX.Element {
return ;
}
+export function BasicWithLabels(): React.JSX.Element {
+ const props = createProps();
+ const conversation = {
+ ...defaultConversation,
+ memberships: [
+ {
+ aci: generateAci(),
+ isAdmin: true,
+ labelString: undefined,
+ labelEmoji: undefined,
+ },
+ {
+ aci: generateAci(),
+ isAdmin: true,
+ labelString: 'First',
+ labelEmoji: undefined,
+ },
+ {
+ aci: generateAci(),
+ isAdmin: false,
+ labelString: 'Second',
+ labelEmoji: undefined,
+ },
+ ],
+ };
+
+ return ;
+}
+
+export function BasicWithNonAdminLabels(): React.JSX.Element {
+ const props = createProps();
+ const conversation = {
+ ...defaultConversation,
+ memberships: [
+ {
+ aci: generateAci(),
+ isAdmin: true,
+ labelString: undefined,
+ labelEmoji: undefined,
+ },
+ {
+ aci: generateAci(),
+ isAdmin: true,
+ labelString: 'First',
+ labelEmoji: undefined,
+ },
+ {
+ aci: generateAci(),
+ isAdmin: false,
+ labelString: 'Second',
+ labelEmoji: undefined,
+ },
+ ],
+ };
+
+ return ;
+}
+
export function NotAdmin(): React.JSX.Element {
return (
!membership.isAdmin && membership.labelString
+ );
const updateAccessControlAttributes = (value: string) => {
+ const newValue = Number(value);
+ if (newValue === AccessControlEnum.ADMINISTRATOR && nonAdminsHaveLabels) {
+ setIsWarningAboutClearingLabels(true);
+ return;
+ }
+
setAccessControlAttributesSetting(conversation.id, Number(value));
};
const updateAccessControlMembers = (value: string) => {
setAccessControlMembersSetting(conversation.id, Number(value));
};
- const AccessControlEnum = Proto.AccessControl.AccessRequired;
const updateAnnouncementsOnly = (value: string) => {
setAnnouncementsOnly(
conversation.id,
@@ -113,6 +126,51 @@ export function GroupV2Permissions({
}
/>
)}
+ {
+ if (!value) {
+ setIsWarningAboutClearingLabels(false);
+ }
+ }}
+ >
+
+
+
+ {i18n('icu:ConversationDetails--label-clear-warning--title')}
+
+
+ {i18n(
+ 'icu:ConversationDetails--label-clear-warning--description'
+ )}
+
+
+
+ {
+ setIsWarningAboutClearingLabels(false);
+ }}
+ >
+ {i18n('icu:cancel')}
+
+ {
+ setAccessControlAttributesSetting(
+ conversation.id,
+ AccessControlEnum.ADMINISTRATOR
+ );
+ setIsWarningAboutClearingLabels(false);
+ }}
+ >
+ {i18n('icu:ConversationDetails--label-clear-warning--continue')}
+
+
+
+
);
}
diff --git a/ts/util/groupMembershipUtils.preload.ts b/ts/util/groupMembershipUtils.preload.ts
index 3859ed5431..b3c81804d1 100644
--- a/ts/util/groupMembershipUtils.preload.ts
+++ b/ts/util/groupMembershipUtils.preload.ts
@@ -195,7 +195,7 @@ export function getMemberships(
aci: member.aci,
labelEmoji: member.labelEmoji,
labelString: member.labelString
- ? truncateString(member.labelString, {
+ ? truncateString(member.labelString.trim(), {
byteLimit: STRING_BYTE_LIMIT,
graphemeLimit: STRING_GRAPHEME_LIMIT,
})