Page MenuHomePhabricator

D8623.id29022.diff
No OneTemporary

D8623.id29022.diff

diff --git a/web/components/menu.css b/web/components/menu.css
--- a/web/components/menu.css
+++ b/web/components/menu.css
@@ -42,6 +42,14 @@
top: 24px;
}
+div.menuActionListRoleActions {
+ font-size: var(--s-font-14);
+ background-color: var(--menu-bg-light);
+ color: var(--menu-color);
+ stroke: var(--menu-color);
+ top: 20px;
+}
+
button.menuAction {
color: inherit;
z-index: 1;
diff --git a/web/components/menu.react.js b/web/components/menu.react.js
--- a/web/components/menu.react.js
+++ b/web/components/menu.react.js
@@ -6,7 +6,11 @@
import css from './menu.css';
import { useRenderMenu } from '../menu-provider.react.js';
-type MenuVariant = 'thread-actions' | 'member-actions' | 'community-actions';
+type MenuVariant =
+ | 'thread-actions'
+ | 'member-actions'
+ | 'community-actions'
+ | 'role-actions';
type MenuProps = {
+icon: React.Node,
@@ -30,6 +34,7 @@
[css.menuActionListThreadActions]: variant === 'thread-actions',
[css.menuActionListMemberActions]: variant === 'member-actions',
[css.menuActionListCommunityActions]: variant === 'community-actions',
+ [css.menuActionListRoleActions]: variant === 'role-actions',
});
const menuActionList = React.useMemo(
diff --git a/web/roles/community-roles-modal.css b/web/roles/community-roles-modal.css
--- a/web/roles/community-roles-modal.css
+++ b/web/roles/community-roles-modal.css
@@ -17,7 +17,7 @@
}
.rolePanelTitle:last-of-type {
- margin-right: 32px;
+ margin-right: 90px;
}
.separator {
diff --git a/web/roles/community-roles-modal.react.js b/web/roles/community-roles-modal.react.js
--- a/web/roles/community-roles-modal.react.js
+++ b/web/roles/community-roles-modal.react.js
@@ -45,6 +45,7 @@
rolePanelEntries.push(
<RolePanelEntry
key={roleName}
+ threadInfo={updatedThreadInfo}
roleName={roleName}
memberCount={roleNamesToMembers[roleName]}
/>,
@@ -52,7 +53,7 @@
});
return rolePanelEntries;
- }, [roleNamesToMembers]);
+ }, [roleNamesToMembers, updatedThreadInfo]);
const rolePermissionsForNewRole = React.useMemo(() => [], []);
diff --git a/web/roles/role-actions-menu.css b/web/roles/role-actions-menu.css
new file mode 100644
--- /dev/null
+++ b/web/roles/role-actions-menu.css
@@ -0,0 +1,4 @@
+.menuContainer {
+ color: var(--menu-color-light);
+ width: 10px;
+}
diff --git a/web/roles/role-actions-menu.react.js b/web/roles/role-actions-menu.react.js
new file mode 100644
--- /dev/null
+++ b/web/roles/role-actions-menu.react.js
@@ -0,0 +1,82 @@
+// @flow
+
+import * as React from 'react';
+
+import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
+
+import css from './role-actions-menu.css';
+import MenuItem from '../components/menu-item.react.js';
+import Menu from '../components/menu.react.js';
+
+const menuIcon = <SWMansionIcon icon="menu-horizontal" size={20} />;
+
+type RoleActionsMenuProps = {
+ +threadInfo: ThreadInfo,
+ +roleName: string,
+};
+
+function RoleActionsMenu(props: RoleActionsMenuProps): React.Node {
+ const { threadInfo, roleName } = props;
+
+ const defaultRoleID = Object.keys(threadInfo.roles).find(
+ roleID => threadInfo.roles[roleID].isDefault,
+ );
+ const existingRoleID = Object.keys(threadInfo.roles).find(
+ roleID => threadInfo.roles[roleID].name === roleName,
+ );
+
+ const isDeletableRole =
+ roleName !== 'Admins' && defaultRoleID !== existingRoleID;
+ const isEditableRole = roleName !== 'Admins';
+
+ const openEditRoleModal = React.useCallback(() => {}, []);
+ const openDeleteRoleModal = React.useCallback(() => {}, []);
+
+ const items = React.useMemo(() => {
+ const availableOptions = [];
+
+ if (isEditableRole) {
+ availableOptions.push({
+ text: 'Edit role',
+ icon: 'edit-1',
+ onClick: openEditRoleModal,
+ dangerous: false,
+ });
+ }
+
+ if (isDeletableRole) {
+ availableOptions.push({
+ text: 'Delete role',
+ icon: 'cross-circle',
+ onClick: openDeleteRoleModal,
+ dangerous: true,
+ });
+ }
+ return availableOptions;
+ }, [isDeletableRole, isEditableRole, openDeleteRoleModal, openEditRoleModal]);
+
+ const roleMenuItems = React.useMemo(
+ () =>
+ items.map(item => (
+ <MenuItem
+ key={item.text}
+ text={item.text}
+ icon={item.icon}
+ onClick={item.onClick}
+ dangerous={item.dangerous}
+ />
+ )),
+ [items],
+ );
+
+ return (
+ <div className={css.menuContainer}>
+ <Menu icon={menuIcon} variant="role-actions">
+ {roleMenuItems}
+ </Menu>
+ </div>
+ );
+}
+
+export default RoleActionsMenu;
diff --git a/web/roles/role-panel-entry.css b/web/roles/role-panel-entry.css
--- a/web/roles/role-panel-entry.css
+++ b/web/roles/role-panel-entry.css
@@ -1,7 +1,5 @@
.rolePanelEntry {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
+ display: grid;
align-items: center;
padding: 12px;
color: var(--community-roles-text-color);
@@ -13,9 +11,16 @@
}
.rolePanelCountEntryContainer {
- margin-right: 40px;
display: flex;
- align-items: flex-end;
+ align-items: center;
+ justify-content: flex-end;
+ grid-column: 3;
+}
+
+.rolePanelCountAndIcon {
+ display: flex;
+ align-items: center;
+ margin-right: 90px;
}
.rolePanelCountEntry {
diff --git a/web/roles/role-panel-entry.react.js b/web/roles/role-panel-entry.react.js
--- a/web/roles/role-panel-entry.react.js
+++ b/web/roles/role-panel-entry.react.js
@@ -2,22 +2,29 @@
import * as React from 'react';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
+
+import RoleActionsMenu from './role-actions-menu.react.js';
import css from './role-panel-entry.css';
import CommIcon from '../CommIcon.react.js';
type RolePanelEntryProps = {
+ +threadInfo: ThreadInfo,
+roleName: string,
+memberCount: number,
};
function RolePanelEntry(props: RolePanelEntryProps): React.Node {
- const { roleName, memberCount } = props;
+ const { threadInfo, roleName, memberCount } = props;
return (
<div className={css.rolePanelEntry}>
<div className={css.rolePanelNameEntry}>{roleName}</div>
<div className={css.rolePanelCountEntryContainer}>
- <div className={css.rolePanelCountEntry}>{memberCount}</div>
- <CommIcon icon="user-filled" size={18} />
+ <div className={css.rolePanelCountAndIcon}>
+ <div className={css.rolePanelCountEntry}>{memberCount}</div>
+ <CommIcon icon="user-filled" size={18} />
+ </div>
+ <RoleActionsMenu threadInfo={threadInfo} roleName={roleName} />
</div>
</div>
);

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 2, 9:20 PM (20 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2608964
Default Alt Text
D8623.id29022.diff (6 KB)

Event Timeline