Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32193708
D8391.1765099179.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D8391.1765099179.diff
View Options
diff --git a/lib/types/thread-permission-types.js b/lib/types/thread-permission-types.js
--- a/lib/types/thread-permission-types.js
+++ b/lib/types/thread-permission-types.js
@@ -84,6 +84,186 @@
export type ThreadPermissionFilterPrefix = $Values<
typeof threadPermissionFilterPrefixes,
>;
+
+const calendarEditPermission = {
+ title: 'Edit calendar',
+ description: 'Allows members to edit the community calendar',
+};
+const editEntries = threadPermissions.EDIT_ENTRIES;
+const descendantEditEntries =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.EDIT_ENTRIES;
+
+const secretChannelsPermission = {
+ title: 'See secret channels',
+ description: 'Allows members to see all secret channels',
+};
+const descendantKnowOf =
+ threadPermissionPropagationPrefixes.DESCENDANT + threadPermissions.KNOW_OF;
+const descendantVisible =
+ threadPermissionPropagationPrefixes.DESCENDANT + threadPermissions.VISIBLE;
+
+const voicedPermission = {
+ title: 'Speak in announcement channels',
+ description: 'Allows members to speak in announcement channels',
+};
+const voiced = threadPermissions.VOICED;
+
+const createAndEditChannelsPermission = {
+ title: 'Create and edit channels',
+ description: 'Allows members to create new and edit existing channels',
+};
+const editThreadName = threadPermissions.EDIT_THREAD_NAME;
+const descendantEditThreadName =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.EDIT_THREAD_NAME;
+const editThreadDescription = threadPermissions.EDIT_THREAD_DESCRIPTION;
+const descendantEditThreadDescription =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.EDIT_THREAD_DESCRIPTION;
+const editThreadColor = threadPermissions.EDIT_THREAD_COLOR;
+const descendantEditThreadColor =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.EDIT_THREAD_COLOR;
+const createSubchannels = threadPermissions.CREATE_SUBCHANNELS;
+const descendantCreateSubchannels =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissionFilterPrefixes.TOP_LEVEL +
+ threadPermissions.CREATE_SUBCHANNELS;
+const editThreadAvatar = threadPermissions.EDIT_THREAD_AVATAR;
+const descendantEditThreadAvatar =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.EDIT_THREAD_AVATAR;
+
+const deleteChannelsPermission = {
+ title: 'Delete channels',
+ description: 'Allows members to delete channels',
+};
+const deleteThread = threadPermissions.DELETE_THREAD;
+const descendantDeleteThread =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.DELETE_THREAD;
+
+const addMembersPermission = {
+ title: 'Add members',
+ description: 'Allows members to add other members to channels',
+};
+const addMembers = threadPermissions.ADD_MEMBERS;
+const descendantAddMembers =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.ADD_MEMBERS;
+
+const removeMembersPermission = {
+ title: 'Remove members',
+ description: 'Allows members to remove other members from channels',
+};
+const removeMembers = threadPermissions.REMOVE_MEMBERS;
+const descendantRemoveMembers =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.REMOVE_MEMBERS;
+
+const changeRolePermission = {
+ title: 'Change roles',
+ description: 'Allows members to change the roles of other members',
+};
+const changeRole = threadPermissions.CHANGE_ROLE;
+const descendantChangeRole =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.CHANGE_ROLE;
+
+const editVisibilityPermission = {
+ title: 'Edit visibility',
+ description: 'Allows members to edit visibility permissions of channels',
+};
+const editPermissions = threadPermissions.EDIT_PERMISSIONS;
+const descendantEditPermissions =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.EDIT_PERMISSIONS;
+
+const managePinsPermission = {
+ title: 'Manage pins',
+ description: 'Allows members to pin or unpin messages in channels',
+};
+const managePins = threadPermissions.MANAGE_PINS;
+const descendantManagePins =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.MANAGE_PINS;
+
+const reactToMessagePermission = {
+ title: 'React to messages',
+ description: 'Allows members to add reactions to messages',
+};
+const reactToMessage = threadPermissions.REACT_TO_MESSAGE;
+const descendantReactToMessage =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.REACT_TO_MESSAGE;
+
+const editMessagePermission = {
+ title: 'Edit messages',
+ description: 'Allows members to edit their sent messages',
+};
+const editMessage = threadPermissions.EDIT_MESSAGE;
+const descendantEditMessage =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.EDIT_MESSAGE;
+
+const manageInviteLinksPermission = {
+ title: 'Manage invite links',
+ description: 'Allows members to create and delete invite links',
+};
+const manageInviteLinks = threadPermissions.MANAGE_INVITE_LINKS;
+const descendantManageInviteLinks =
+ threadPermissionPropagationPrefixes.DESCENDANT +
+ threadPermissions.MANAGE_INVITE_LINKS;
+
+export type ConfigurableCommunityPermissionOption = {
+ title: string,
+ description: string,
+};
+type ConfigurableCommunityPermission = {
+ [permission: string]: ConfigurableCommunityPermissionOption,
+};
+
+export const configurableCommunityPermissions: ConfigurableCommunityPermission =
+ Object.freeze({
+ [editEntries]: calendarEditPermission,
+ [descendantEditEntries]: calendarEditPermission,
+ [descendantKnowOf]: secretChannelsPermission,
+ [descendantVisible]: secretChannelsPermission,
+ [voiced]: voicedPermission,
+ [editThreadName]: createAndEditChannelsPermission,
+ [descendantEditThreadName]: createAndEditChannelsPermission,
+ [editThreadDescription]: createAndEditChannelsPermission,
+ [descendantEditThreadDescription]: createAndEditChannelsPermission,
+ [editThreadColor]: createAndEditChannelsPermission,
+ [descendantEditThreadColor]: createAndEditChannelsPermission,
+ [createSubchannels]: createAndEditChannelsPermission,
+ [descendantCreateSubchannels]: createAndEditChannelsPermission,
+ [editThreadAvatar]: createAndEditChannelsPermission,
+ [descendantEditThreadAvatar]: createAndEditChannelsPermission,
+ [deleteThread]: deleteChannelsPermission,
+ [descendantDeleteThread]: deleteChannelsPermission,
+ [addMembers]: addMembersPermission,
+ [descendantAddMembers]: addMembersPermission,
+ [removeMembers]: removeMembersPermission,
+ [descendantRemoveMembers]: removeMembersPermission,
+ [changeRole]: changeRolePermission,
+ [descendantChangeRole]: changeRolePermission,
+ [editPermissions]: editVisibilityPermission,
+ [descendantEditPermissions]: editVisibilityPermission,
+ [managePins]: managePinsPermission,
+ [descendantManagePins]: managePinsPermission,
+ [reactToMessage]: reactToMessagePermission,
+ [descendantReactToMessage]: reactToMessagePermission,
+ [editMessage]: editMessagePermission,
+ [descendantEditMessage]: editMessagePermission,
+ [manageInviteLinks]: manageInviteLinksPermission,
+ [descendantManageInviteLinks]: manageInviteLinksPermission,
+ });
+
+export const configurableCommunityPermissionsOptions: $ReadOnlySet<ConfigurableCommunityPermissionOption> =
+ new Set(values(configurableCommunityPermissions));
+
export type ThreadPermissionInfo =
| { +value: true, +source: string }
| { +value: false, +source: null };
diff --git a/lib/utils/objects.js b/lib/utils/objects.js
--- a/lib/utils/objects.js
+++ b/lib/utils/objects.js
@@ -116,4 +116,15 @@
);
}
-export { findMaximumDepth, values, hash, assertObjectsAreEqual, deepDiff };
+function getKeysByValue<K, T>(obj: ObjectMap<K, T>, value: T): K[] {
+ return Object.keys(obj).filter((key: K) => obj[key] === value);
+}
+
+export {
+ findMaximumDepth,
+ values,
+ hash,
+ assertObjectsAreEqual,
+ deepDiff,
+ getKeysByValue,
+};
diff --git a/native/roles/create-roles-screen.react.js b/native/roles/create-roles-screen.react.js
--- a/native/roles/create-roles-screen.react.js
+++ b/native/roles/create-roles-screen.react.js
@@ -1,11 +1,22 @@
// @flow
import * as React from 'react';
+import { View, Text, TouchableOpacity, ScrollView } from 'react-native';
+import {
+ configurableCommunityPermissions,
+ configurableCommunityPermissionsOptions,
+ type ConfigurableCommunityPermissionOption,
+} from 'lib/types/thread-permission-types.js';
import type { ThreadInfo } from 'lib/types/thread-types.js';
+import { getKeysByValue } from 'lib/utils/objects.js';
import type { RolesNavigationProp } from './roles-navigator.react.js';
+import EnumSettingsOption from '../components/enum-settings-option.react.js';
+import SWMansionIcon from '../components/swmansion-icon.react.js';
+import TextInput from '../components/text-input.react.js';
import type { NavigationRoute } from '../navigation/route-names.js';
+import { useStyles } from '../themes/colors.js';
export type CreateRolesScreenParams = {
+threadInfo: ThreadInfo,
@@ -17,9 +28,183 @@
+route: NavigationRoute<'CreateRolesScreen'>,
};
-// eslint-disable-next-line no-unused-vars
function CreateRolesScreen(props: CreateRolesScreenProps): React.Node {
- return <></>;
+ // eslint-disable-next-line no-unused-vars
+ const { threadInfo, action } = props.route.params;
+
+ const [customRoleName, setCustomRoleName] =
+ React.useState<string>('New Role');
+ const [selectedPermissions, setSelectedPermissions] = React.useState([]);
+
+ const styles = useStyles(unboundStyles);
+
+ const onClearPermissions = React.useCallback(() => {
+ setSelectedPermissions([]);
+ }, []);
+
+ const isSelectedPermissionsEmpty = selectedPermissions.length === 0;
+ const clearPermissionsText = React.useMemo(() => {
+ if (isSelectedPermissionsEmpty) {
+ return (
+ <Text style={styles.clearPermissionsTextDisabled}>
+ Clear permissions
+ </Text>
+ );
+ }
+
+ return (
+ <TouchableOpacity onPress={onClearPermissions}>
+ <Text style={styles.clearPermissionsText}>Clear permissions</Text>
+ </TouchableOpacity>
+ );
+ }, [
+ isSelectedPermissionsEmpty,
+ onClearPermissions,
+ styles.clearPermissionsText,
+ styles.clearPermissionsTextDisabled,
+ ]);
+
+ const isUserFacingPermissionSelected = React.useCallback(
+ (option: ConfigurableCommunityPermissionOption) => {
+ const associatedPermissions = getKeysByValue(
+ configurableCommunityPermissions,
+ option,
+ );
+
+ return associatedPermissions.every(permission =>
+ selectedPermissions.includes(permission),
+ );
+ },
+ [selectedPermissions],
+ );
+
+ const onEnumValuePress = React.useCallback(
+ (option: ConfigurableCommunityPermissionOption) => {
+ // configurableCommunityPermissions is an object where one permission
+ // is associated with exactly one user-facing option. This means that
+ // permission propagation are classed as separate entries in the object.
+ // So, for example, 'edit_entries' and 'descendants_edit_entries' are
+ // separate entries in the object, but they are both associated with the
+ // same user-facing option, 'Edit entries'. So when a user-facing option
+ // is selected, we need to select all permissions associated with that.
+ const associatedPermissions = getKeysByValue(
+ configurableCommunityPermissions,
+ option,
+ );
+
+ // Toggle the inclusivity of the permissions associated with the
+ // user-facing option.
+ if (isUserFacingPermissionSelected(option)) {
+ setSelectedPermissions(currentPermissions =>
+ currentPermissions.filter(
+ permission => !associatedPermissions.includes(permission),
+ ),
+ );
+ } else {
+ setSelectedPermissions(currentPermissions => [
+ ...currentPermissions,
+ ...associatedPermissions,
+ ]);
+ }
+ },
+ [isUserFacingPermissionSelected],
+ );
+
+ const permissionsList = React.useMemo(
+ () =>
+ [...configurableCommunityPermissionsOptions].map(permission => (
+ <EnumSettingsOption
+ key={permission.title}
+ name={permission.title}
+ description={permission.description}
+ enumValue={isUserFacingPermissionSelected(permission)}
+ onEnumValuePress={() => onEnumValuePress(permission)}
+ />
+ )),
+ [isUserFacingPermissionSelected, onEnumValuePress],
+ );
+
+ const onChangeRoleNameInput = React.useCallback((roleName: string) => {
+ setCustomRoleName(roleName);
+ }, []);
+
+ return (
+ <View>
+ <View style={styles.roleNameContainer}>
+ <Text style={styles.roleNameText}>ROLE NAME</Text>
+ <View style={styles.roleInput}>
+ <TextInput
+ style={styles.roleInputComponent}
+ value={customRoleName}
+ onChangeText={onChangeRoleNameInput}
+ editable={true}
+ />
+ <SWMansionIcon name="edit-1" size={20} style={styles.pencilIcon} />
+ </View>
+ </View>
+ <View style={styles.permissionsContainer}>
+ <View style={styles.permissionsHeader}>
+ <Text style={styles.permissionsText}>PERMISSIONS</Text>
+ {clearPermissionsText}
+ </View>
+ <ScrollView style={styles.permissionsListContainer}>
+ {permissionsList}
+ </ScrollView>
+ </View>
+ </View>
+ );
}
+const unboundStyles = {
+ roleNameContainer: {
+ marginTop: 30,
+ },
+ roleNameText: {
+ color: 'panelBackgroundLabel',
+ fontSize: 12,
+ marginBottom: 5,
+ marginLeft: 10,
+ },
+ roleInput: {
+ backgroundColor: 'panelForeground',
+ padding: 12,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ roleInputComponent: {
+ color: 'whiteText',
+ fontSize: 16,
+ },
+ pencilIcon: {
+ color: 'panelInputSecondaryForeground',
+ },
+ permissionsContainer: {
+ marginTop: 20,
+ paddingBottom: 220,
+ },
+ permissionsHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ permissionsText: {
+ color: 'panelBackgroundLabel',
+ fontSize: 12,
+ marginLeft: 10,
+ },
+ clearPermissionsText: {
+ color: 'purpleLink',
+ fontSize: 12,
+ marginRight: 15,
+ },
+ clearPermissionsTextDisabled: {
+ color: 'disabledButton',
+ fontSize: 12,
+ marginRight: 15,
+ },
+ permissionsListContainer: {
+ backgroundColor: 'panelForeground',
+ marginTop: 10,
+ },
+};
+
export default CreateRolesScreen;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 7, 9:19 AM (14 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5843275
Default Alt Text
D8391.1765099179.diff (14 KB)
Attached To
Mode
D8391: [native] Populate the create role screen
Attached
Detach File
Event Timeline
Log In to Comment