diff --git a/frontend/src/App/App.jsx b/frontend/src/App/App.jsx index 0f1043c2dd..bf735d61fc 100644 --- a/frontend/src/App/App.jsx +++ b/frontend/src/App/App.jsx @@ -38,6 +38,7 @@ import { ManageGroupPermissions } from '@/ManageGroupPermissions'; import OrganizationLogin from '@/_components/OrganizationLogin/OrganizationLogin'; import { ManageOrgVars } from '@/ManageOrgVars'; import { useAppDataStore } from '@/_stores/appDataStore'; +import { ManageGroupPermissionsV2 } from '@/ManageGroupPermissionsV2/ManageGroupPermissionsV2'; const AppWrapper = (props) => { const { isAppDarkMode } = useAppDarkMode(); @@ -275,6 +276,14 @@ class AppComponent extends React.Component { } /> + + + + } + /> } diff --git a/frontend/src/ManageGranularAccess/index.jsx b/frontend/src/ManageGranularAccess/index.jsx new file mode 100644 index 0000000000..61900381b8 --- /dev/null +++ b/frontend/src/ManageGranularAccess/index.jsx @@ -0,0 +1,193 @@ +import { ButtonSolid } from '@/_ui/AppButton/AppButton'; +import SolidIcon from '@/_ui/Icon/SolidIcons'; +import ModalBase from '@/_ui/Modal'; +import { AppsSelect } from '@/_ui/Modal/AppsSelect'; +import Multiselect from '@/_ui/Multiselect/Multiselect'; +import React from 'react'; +import { OverlayTrigger } from 'react-bootstrap'; +import { withTranslation } from 'react-i18next'; + +class ManageGranularAccessComponent extends React.Component { + constructor(props) { + super(props); + + this.state = { + isEmpty: true, + showAddPermissionModal: false, + errors: {}, + values: {}, + customSelected: true, + selectedApps: [], + }; + } + + openAddPermissionModal = () => this.setState({ showAddPermissionModal: true }); + + clsoseAddPermissionModal = () => this.setState({ showAddPermissionModal: false }); + + setSelectedApps = (values) => this.setState({ selectedApps: values }); + + render() { + const { isEmpty, showAddPermissionModal, errors, selectedApps } = this.state; + const apps = [ + { name: 'App 1', value: 'App1', label: 'app 1' }, + { name: 'App Long name 1', value: 'App2', label: 'app long name 1' }, + { name: 'App very long name', value: 'App3', label: 'app very long name' }, + { name: 'App 4', value: 'App4', label: 'app 4' }, + { name: 'App5veryverylongname', value: 'App5veryverylongname', label: 'App5veryverylongname' }, + { name: 'App 6', value: 'App6', label: '6' }, + { name: 'App 7', value: 'App 7', label: 'app 7' }, + { name: 'App 8', value: 'App 8', label: 'app 8' }, + { name: 'App 9', value: 'App 9', label: 'app 9' }, + { name: 'App 10', value: 'App 10', label: 'app 10' }, + { name: 'App 11', value: 'App 11', label: 'app 11' }, + { name: 'App 12', value: 'App 12', label: 'app 12' }, + ]; + + return ( +
+ + + + +
+ Add app permissions +
+
+ } + confirmBtnProps={{ title: 'Add', iconLeft: 'plus' }} + darkMode={this.props.darkMode} + > +
+ +
+ + {errors['permissionName']} +
+
+
Permission name must be unique and max 50 characters
+
+
+
+ +
+
+ +
+
+ + +
+
+
+
+ +
+ + + +
+
+ + {isEmpty ? ( +
+
+ +
+

No permissions added yet

+

+ Add assets to configure granular, asset-level permissions for this user group +

+ + { + this.openAddPermissionModal(); + }} + > + Apps + +
+ } + > +
+ { + // this.openChangeRoleModal(user); + }} + > + Add permission + +
+ + + ) : ( +
+ )} + + ); + } +} + +export const ManageGranularAccess = withTranslation()(ManageGranularAccessComponent); diff --git a/frontend/src/ManageGroupPermissionResourcesV2/index.jsx b/frontend/src/ManageGroupPermissionResourcesV2/index.jsx new file mode 100644 index 0000000000..1333b474e8 --- /dev/null +++ b/frontend/src/ManageGroupPermissionResourcesV2/index.jsx @@ -0,0 +1,1005 @@ +import React from 'react'; +import cx from 'classnames'; +import { groupPermissionService } from '@/_services'; +import { toast } from 'react-hot-toast'; +import { Link } from 'react-router-dom'; +import { withTranslation } from 'react-i18next'; +import ErrorBoundary from '@/Editor/ErrorBoundary'; +import { Loader } from '../ManageSSO/Loader'; +import SolidIcon from '@/_ui/Icon/solidIcons/index'; +import BulkIcon from '@/_ui/Icon/bulkIcons/index'; +import Multiselect from '@/_ui/Multiselect/Multiselect'; +import { FilterPreview, MultiSelectUser } from '@/_components'; +import { ButtonSolid } from '@/_ui/AppButton/AppButton'; +import ModalBase from '@/_ui/Modal'; +import Select from '@/_ui/Select'; +import { ManageGranularAccess } from '@/ManageGranularAccess'; + +class ManageGroupPermissionResourcesComponent extends React.Component { + constructor(props) { + super(props); + + this.state = { + isLoadingGroup: true, + isLoadingApps: true, + isAddingApps: false, + isLoadingUsers: true, + isAddingUsers: false, + groupPermission: null, + usersInGroup: [], + appsInGroup: [], + usersNotInGroup: [], + appsNotInGroup: [], + selectedAppIds: [], + removeAppIds: [], + currentTab: 'users', + selectedUsers: [], + isChangeRoleModalOpen: false, + updatingUserRole: null, + isAddUsersToRoleModalOpen: false, + }; + } + + componentDidMount() { + if (this.props.groupPermissionId) this.fetchGroupAndResources(this.props.groupPermissionId); + } + + componentDidUpdate(prevProps) { + if (this.props.groupPermissionId && this.props.groupPermissionId !== prevProps.groupPermissionId) { + this.fetchGroupAndResources(this.props.groupPermissionId); + } + } + + fetchGroupPermission = (groupPermissionId) => { + groupPermissionService.getGroup(groupPermissionId).then((data) => { + this.setState((prevState) => { + return { + groupPermission: data, + currentTab: prevState.currentTab, + isLoadingGroup: false, + }; + }); + }); + }; + + fetchGroupAndResources = (groupPermissionId) => { + this.setState({ isLoadingGroup: true }); + this.fetchGroupPermission(groupPermissionId); + this.fetchUsersInGroup(groupPermissionId); + this.fetchAppsNotInGroup(groupPermissionId); + this.fetchAppsInGroup(groupPermissionId); + }; + + userFullName = (user) => { + return `${user?.first_name} ${user?.last_name ?? ''}`; + }; + + searchUsersNotInGroup = async (query, groupPermissionId) => { + return new Promise((resolve, reject) => { + groupPermissionService + .getUsersNotInGroup(query, groupPermissionId) + .then(({ users }) => { + resolve( + users.map((user) => { + return { + name: `${this.userFullName(user)} (${user.email})`, + value: user.id, + first_name: user.first_name, + last_name: user.last_name, + email: user.email, + }; + }) + ); + }) + .catch(reject); + }); + }; + + fetchUsersInGroup = (groupPermissionId) => { + groupPermissionService.getUsersInGroup(groupPermissionId).then((data) => { + this.setState({ + usersInGroup: data.users, + isLoadingUsers: false, + }); + }); + }; + + fetchAppsNotInGroup = (groupPermissionId) => { + groupPermissionService.getAppsNotInGroup(groupPermissionId).then((data) => { + this.setState({ + appsNotInGroup: data.apps, + }); + }); + }; + + fetchAppsInGroup = (groupPermissionId) => { + groupPermissionService.getAppsInGroup(groupPermissionId).then((data) => { + this.setState({ + appsInGroup: data.apps, + isLoadingApps: false, + }); + }); + }; + + updateGroupPermission = (groupPermissionId, params) => { + groupPermissionService + .update(groupPermissionId, params) + .then(() => { + toast.success('Group permissions updated'); + this.fetchGroupPermission(groupPermissionId); + }) + .catch(({ error }) => { + toast.error(error); + }); + }; + + updateAppGroupPermission = (app, groupPermissionId, action) => { + const appGroupPermission = app.app_group_permissions.find( + (permission) => permission.group_permission_id === groupPermissionId + ); + + let actionParams = { + read: true, + update: action === 'edit', + }; + + if (action === 'hideFromDashboard') { + actionParams['hideFromDashboard'] = !this.canAppGroupPermission(app, groupPermissionId, 'hideFromDashboard'); + } + + if (action === 'edit') actionParams['hideFromDashboard'] = false; + + groupPermissionService + .updateAppGroupPermission(groupPermissionId, appGroupPermission.id, actionParams) + .then(() => { + toast.success('App permissions updated'); + + this.fetchAppsInGroup(groupPermissionId); + }) + .catch(({ error }) => { + toast.error(error); + }); + }; + + canAppGroupPermission = (app, groupPermissionId, action) => { + let appGroupPermission = this.findAppGroupPermission(app, groupPermissionId); + switch (action) { + case 'edit': + return appGroupPermission?.read && appGroupPermission?.update; + case 'view': + return appGroupPermission?.read && !appGroupPermission?.update; + case 'hideFromDashboard': + return appGroupPermission?.read && appGroupPermission?.read_on_dashboard; + default: + return false; + } + }; + + findAppGroupPermission = (app, groupPermissionId) => { + return app.app_group_permissions.find((permission) => permission.group_permission_id === groupPermissionId); + }; + + setSelectedUsers = (value) => { + this.setState({ + selectedUsers: value, + }); + }; + + setSelectedApps = (value) => { + this.setState({ + selectedAppIds: value, + }); + }; + + addSelectedAppsToGroup = (groupPermissionId) => { + this.setState({ isAddingApps: true }); + const updateParams = { + add_apps: this.state.selectedAppIds.map((app) => app.value), + }; + groupPermissionService + .update(groupPermissionId, updateParams) + .then(() => { + this.setState({ + selectedAppIds: [], + isLoadingApps: true, + isAddingApps: false, + }); + this.fetchAppsNotInGroup(groupPermissionId); + this.fetchAppsInGroup(groupPermissionId); + }) + .then(() => { + toast.success('Apps added to the group'); + this.setState({ + selectedApps: [], + }); + }) + .catch(({ error }) => { + toast.error(error); + }); + }; + + removeAppFromGroup = (groupPermissionId, appId, appName) => { + if (window.confirm(`Are you sure you want to delete this app - ${appName}?`) === false) return; + const updateParams = { + remove_apps: [appId], + }; + groupPermissionService + .update(groupPermissionId, updateParams) + .then(() => { + this.setState({ removeAppIds: [], isLoadingApps: true }); + this.fetchAppsNotInGroup(groupPermissionId); + this.fetchAppsInGroup(groupPermissionId); + }) + .then(() => { + toast.success('App removed from the group'); + }) + .catch(({ error }) => { + toast.error(error); + }); + }; + + addSelectedUsersToGroup = (groupPermissionId, selectedUsers) => { + this.setState({ isAddingUsers: true }); + const updateParams = { + add_users: selectedUsers.map((user) => user.value), + }; + groupPermissionService + .update(groupPermissionId, updateParams) + .then(() => { + this.setState({ + selectedUsers: [], + isLoadingUsers: true, + isAddingUsers: false, + }); + this.fetchUsersInGroup(groupPermissionId); + }) + .then(() => { + toast.success('Users added to the group'); + }) + .catch(({ error }) => { + toast.error(error); + }); + }; + + removeUserFromGroup = (groupPermissionId, userId) => { + const updateParams = { + remove_users: [userId], + }; + groupPermissionService + .update(groupPermissionId, updateParams) + .then(() => { + this.setState({ removeUserIds: [], isLoadingUsers: true }); + this.fetchUsersInGroup(groupPermissionId); + }) + .then(() => { + toast.success('User removed from the group'); + }) + .catch(({ error }) => { + toast.error(error); + }); + }; + + removeSelection = (selected, value) => { + const updatedData = selected.filter((d) => d.value !== value); + this.setSelectedUsers([...updatedData]); + }; + + openChangeRoleModal = (updatingUser) => + this.setState({ isChangeRoleModalOpen: true, updatingUserRole: updatingUser }); + + closeChangeRoleModal = () => this.setState({ isChangeRoleModalOpen: false, updatingUserRole: null }); + + toggleAddUsersToRoleModal = () => this.setState({ isAddUsersToRoleModalOpen: !this.state.isAddUsersToRoleModalOpen }); + + render() { + if (!this.props.groupPermissionId) return null; + + const { + isLoadingGroup, + isLoadingApps, + isAddingApps, + isLoadingUsers, + isAddingUsers, + appsInGroup, + appsNotInGroup, + usersInGroup, + groupPermission, + currentTab, + selectedAppIds, + selectedUsers, + isChangeRoleModalOpen, + isAddUsersToRoleModalOpen, + updatingUserRole, + } = this.state; + + const searchSelectClass = this.props.darkMode ? 'select-search-dark' : 'select-search'; + + const folder_permission = groupPermission + ? groupPermission.folder_create && groupPermission.folder_delete && groupPermission.folder_update + : false; + + const appSelectOptions = appsNotInGroup.map((app) => { + return { name: app.name, value: app.id }; + }); + + const orgEnvironmentPermission = groupPermission + ? groupPermission.org_environment_variable_create && + groupPermission.org_environment_variable_update && + groupPermission.org_environment_variable_delete + : false; + + return ( + + + Edit user role +
+ {updatingUserRole?.email} +
+ + } + show={isChangeRoleModalOpen} + handleClose={this.closeChangeRoleModal} + confirmBtnProps={{ title: 'Save changes' }} + darkMode={this.props.darkMode} + > + + { + this.updateAppGroupPermission(app, groupPermission.id, 'view'); + }} + disabled={groupPermission.group === 'admin'} + checked={this.canAppGroupPermission(app, groupPermission.id, 'view')} + data-cy="checkbox-view-app" + /> + + {this.props.t('globals.view', 'view')} + + + + +
+ +
+ + + {groupPermission.group !== 'admin' && ( + { + this.removeAppFromGroup(groupPermission.id, app.id, app.name); + }} + className="delete-link" + > + + Remove + + + )} + + + )) + ) : ( +
+
+ +
+

+ No apps are added to the group +

+ + Add app to the group to control permissions +
for users in this group +
+
+ )} + + )} + + + + + + + {/* Users Tab */} +
+ {groupPermission?.group !== 'all_users' && ( +
+
+ this.searchUsersNotInGroup(query, groupPermission.id)} + selectedValues={selectedUsers} + onReset={() => this.setSelectedUsers([])} + placeholder="Select users to add to the group" + searchLabel="Enter name or email" + /> +
+
+ + Add users + +
+
+ )} +
+
+ {groupPermission.group == 'all_users' && ( +
+

+ All users within the workspace are included + in this list. This list cannot be edited. +

+
+ )} +
+

+ User name +

+

+ Email id +

+

{/* DO NOT REMOVE FOR TABLE ALIGNMENT */} +
+
+ {isLoadingGroup || isLoadingUsers ? ( + + +
+
+
+ + +
+ + +
+ + + ) : usersInGroup.length > 0 ? ( + usersInGroup.map((user) => ( +
+

+

+ {`${user?.first_name?.[0] ?? ''} ${user?.last_name?.[0] ?? ''}`} +
+ {`${user?.first_name ?? ''} ${user?.last_name ?? ''}`} +

+

+ {user.email} +

+

+ {groupPermission.group !== 'all_users' && ( + + { + this.removeUserFromGroup(groupPermission.id, user.id); + }} + > + {this.props.t('globals.delete', 'Delete')} + + + )} +

+

+ { + this.openChangeRoleModal(user); + }} + > + Edit role + +

+
+ )) + ) : ( +
+
+ +
+

+ No users added yet +

+ + Add users to this group to configure +
permissions for them! +
+
+ )} +
+
+
+ + {/* Permissions Tab */} + + + + {/* Granular Access */} + + + + + )} + +
+ ); + } +} + +export const ManageGroupPermissionResourcesV2 = withTranslation()(ManageGroupPermissionResourcesComponent); diff --git a/frontend/src/ManageGroupPermissionsV2/ManageGroupPermissionsV2.jsx b/frontend/src/ManageGroupPermissionsV2/ManageGroupPermissionsV2.jsx new file mode 100644 index 0000000000..c334f0ea18 --- /dev/null +++ b/frontend/src/ManageGroupPermissionsV2/ManageGroupPermissionsV2.jsx @@ -0,0 +1,626 @@ +import React from 'react'; +import { groupPermissionService } from '@/_services'; +import { Tooltip } from 'react-tooltip'; +import { ConfirmDialog } from '@/_components'; +import { toast } from 'react-hot-toast'; +import { withTranslation } from 'react-i18next'; +import ErrorBoundary from '@/Editor/ErrorBoundary'; +import Modal from '../HomePage/Modal'; +import { ButtonSolid } from '@/_ui/AppButton/AppButton'; +import FolderList from '@/_ui/FolderList/FolderList'; +import { Loader } from '../ManageSSO/Loader'; +import Popover from 'react-bootstrap/Popover'; +import SolidIcon from '@/_ui/Icon/solidIcons/index'; +import ModalBase from '@/_ui/Modal'; +import OverflowTooltip from '@/_components/OverflowTooltip'; +import { ManageGroupPermissionResourcesV2 } from '@/ManageGroupPermissionResourcesV2'; +class ManageGroupPermissionsComponent extends React.Component { + constructor(props) { + super(props); + + this.state = { + isLoading: true, + groups: [], + creatingGroup: false, + showNewGroupForm: false, + newGroupName: null, + isDeletingGroup: false, + isUpdatingGroupName: false, + showGroupDeletionConfirmation: false, + showGroupNameUpdateForm: false, + groupToBeUpdated: null, + isSaveBtnDisabled: false, + selectedGroupPermissionId: null, + selectedGroup: 'All users', + isDuplicatingGroup: false, + groupDuplicateOption: { addPermission: true, addApps: true, addUsers: true }, + showDuplicateGroupModal: false, + groupToDuplicate: '', + }; + } + + componentDidMount() { + this.fetchGroups(); + } + + findCurrentGroupDetails = (data) => { + let currentUpdatedGroup = data.group_permissions.find((item) => { + return item.group == this.state.newGroupName; + }); + this.setState({ selectedGroup: currentUpdatedGroup.group }); + return currentUpdatedGroup.id; + }; + + duplicateGroup = () => { + const { groupDuplicateOption, groupToDuplicate } = this.state; + this.setState({ isDuplicatingGroup: true, creatingGroup: true }); + groupPermissionService + .duplicate(groupToDuplicate, groupDuplicateOption) + .then((data) => { + this.setState({ + newGroupName: data?.group, + }); + this.fetchGroups('current', () => { + this.setState({ + newGroupName: '', + creatingGroup: false, + selectedGroupPermissionId: data?.id, + selectedGroup: data?.group, + isDuplicatingGroup: false, + showDuplicateGroupModal: false, + groupDuplicateOption: { addPermission: true, addApps: true, addUsers: true }, + }); + }); + + toast.success('Group duplicated successfully!'); + }) + .catch((err) => { + this.setState({ + isDuplicatingGroup: false, + groupDuplicateOption: { addPermission: true, addApps: true, addUsers: true }, + }); + console.error('Error occured in duplicating: ', err); + toast.error('Could not duplicate group.\nPlease try again!'); + }); + }; + + toggleShowDuplicateModal = () => { + this.setState((prevState) => ({ + showDuplicateGroupModal: !prevState.showDuplicateGroupModal, + groupToDuplicate: '', + groupDuplicateOption: { addPermission: true, addApps: true, addUsers: true }, + })); + }; + + renderPopoverContent = (props, compoParam) => { + const { groupName, id } = compoParam; + const deleteGroup = () => { + this.deleteGroup(id); + }; + + const duplicateGroup = () => { + this.showDuplicateDiologBox(id); + }; + + const isDefaultGroup = groupName == 'all_users' || groupName == 'admin'; + + return ( +
+ + +
+ + +
+
+
+ {(groupName == 'all_users' || groupName == 'admin') && ( + + )} +
+ ); + }; + + fetchGroups = (type = 'admin', callback = () => {}) => { + this.setState({ + isLoading: true, + }); + + groupPermissionService + .getGroups() + .then((data) => { + this.setState( + { + groups: data.group_permissions, + isLoading: false, + selectedGroupPermissionId: + type == 'admin' + ? data.group_permissions[0].id + : type == 'current' + ? this.findCurrentGroupDetails(data) + : data.group_permissions.at(-1).id, + }, + callback + ); + }) + .catch(({ error }) => { + toast.error(error); + this.setState({ + isLoading: false, + }); + }); + }; + + changeNewGroupName = (value) => { + this.setState({ + newGroupName: value, + isSaveBtnDisabled: false, + }); + if ((this.state.groupToBeUpdated && this.state.groupToBeUpdated.group === value) || !value) { + this.setState({ + isSaveBtnDisabled: true, + }); + } + }; + + humanizeifDefaultGroupName = (groupName) => { + switch (groupName) { + case 'all_users': + return 'All users'; + + case 'admin': + return 'Admin'; + + default: + return groupName; + } + }; + + createGroup = () => { + this.setState({ creatingGroup: true }); + groupPermissionService + .create(this.state.newGroupName) + .then(() => { + this.setState({ + creatingGroup: false, + showNewGroupForm: false, + newGroupName: null, + selectedGroup: this.state.newGroupName, + }); + toast.success('Group has been created'); + this.fetchGroups('new'); + }) + .catch(({ error }) => { + toast.error(error); + this.setState({ + creatingGroup: false, + showNewGroupForm: true, + }); + }); + }; + + deleteGroup = (groupPermissionId) => { + this.setState({ + showGroupDeletionConfirmation: true, + groupToBeDeleted: groupPermissionId, + }); + }; + + updateGroupName = (groupPermission) => { + this.setState({ + showGroupNameUpdateForm: true, + groupToBeUpdated: groupPermission, + newGroupName: groupPermission.group, + isSaveBtnDisabled: true, + }); + }; + + cancelDeleteGroupDialog = () => { + this.setState({ + isDeletingGroup: false, + groupToBeDeleted: null, + showGroupDeletionConfirmation: false, + }); + }; + + executeGroupDeletion = () => { + this.setState({ isDeletingGroup: true }); + groupPermissionService + .del(this.state.groupToBeDeleted) + .then(() => { + toast.success('Group deleted successfully'); + this.fetchGroups(); + this.setState({ selectedGroup: 'All users', isDeletingGroup: false }); + }) + .catch(({ error }) => { + toast.error(error); + }) + .finally(() => { + this.cancelDeleteGroupDialog(); + }); + }; + + showDuplicateDiologBox = (id) => { + this.setState({ groupToDuplicate: id, showDuplicateGroupModal: true, isDuplicatingGroup: false }); + }; + + executeGroupUpdation = () => { + this.setState({ isUpdatingGroupName: true, selectedGroup: this.state.newGroupName }); + groupPermissionService + .update(this.state.groupToBeUpdated?.id, { name: this.state.newGroupName }) + .then(() => { + toast.success('Group name updated successfully'); + this.fetchGroups('current'); + this.setState({ + isUpdatingGroupName: false, + groupToBeUpdated: null, + showGroupNameUpdateForm: false, + }); + }) + .catch(({ error }) => { + toast.error(error); + this.setState({ + isUpdatingGroupName: false, + }); + }); + }; + + render() { + const { + isLoading, + showNewGroupForm, + showGroupNameUpdateForm, + creatingGroup, + isUpdatingGroupName, + groups, + isDeletingGroup, + showGroupDeletionConfirmation, + showDuplicateGroupModal, + isDuplicatingGroup, + groupDuplicateOption, + } = this.state; + + const { addPermission, addApps, addUsers } = groupDuplicateOption; + const allFalse = [addPermission, addApps, addUsers].every((value) => !value); + + return ( + +
+
+ this.executeGroupDeletion()} + onCancel={() => this.cancelDeleteGroupDialog()} + darkMode={this.props.darkMode} + /> + +
+ Duplicate the following parts of the group +
+
+
+
+ { + this.setState((prevState) => ({ + groupDuplicateOption: { + ...prevState.groupDuplicateOption, + addUsers: !prevState.groupDuplicateOption.addUsers, + }, + })); + }} + data-cy="users-check-input" + /> +
+
+
+ Users +
+
+
+
+
+ { + this.setState((prevState) => ({ + groupDuplicateOption: { + ...prevState.groupDuplicateOption, + addPermission: !prevState.groupDuplicateOption.addPermission, + }, + })); + }} + data-cy="permissions-check-input" + /> +
+
+
+ Permissions +
+
+
+
+
+ { + this.setState((prevState) => ({ + groupDuplicateOption: { + ...prevState.groupDuplicateOption, + addApps: !prevState.groupDuplicateOption.addApps, + }, + })); + }} + data-cy="apps-check-input" + /> +
+
+
+ Apps +
+
+
+
+
+
+

+ {groups?.length} Groups +

+ {!showNewGroupForm && !showGroupNameUpdateForm && ( + { + e.preventDefault(); + this.setState({ newGroupName: null, showNewGroupForm: true, isSaveBtnDisabled: true }); + }} + data-cy="create-new-group-button" + leftIcon="plus" + isLoading={isLoading} + iconWidth="16" + fill={'#FDFDFE'} + > + {this.props.t( + 'header.organization.menus.manageGroups.permissions.createNewGroup', + 'Create new group' + )} + + )} +
+ + + this.setState({ + showNewGroupForm: false, + showGroupNameUpdateForm: false, + newGroupName: null, + }) + } + title={ + showGroupNameUpdateForm + ? this.props.t('header.organization.menus.manageGroups.permissions.updateGroup', 'Update group') + : this.props.t('header.organization.menus.manageGroups.permissions.addNewGroup', 'Add new group') + } + > +
{ + e.preventDefault(); + if (showNewGroupForm) { + this.createGroup(); + } else { + this.executeGroupUpdation(); + } + }} + > +
+
+
+ { + this.changeNewGroupName(e.target.value); + }} + value={this.state.newGroupName} + data-cy="group-name-input" + autoFocus + /> +
+
+
+
+ + this.setState({ + showNewGroupForm: false, + showGroupNameUpdateForm: false, + newGroupName: null, + }) + } + disabled={creatingGroup} + data-cy="cancel-button" + variant="tertiary" + > + {this.props.t('globals.cancel', 'Cancel')} + + + {showGroupNameUpdateForm + ? this.props.t('globals.save', 'Save') + : this.props.t('header.organization.menus.manageGroups.permissions.createGroup', 'Create Group')} + +
+
+
+ + {!showNewGroupForm && !showGroupNameUpdateForm && ( +
+
+
+ + USER ROLE +
+ {groups.map((permissionGroup) => { + return ( + { + this.setState({ + selectedGroupPermissionId: permissionGroup.id, + selectedGroup: this.humanizeifDefaultGroupName(permissionGroup.group), + }); + }} + toolTipText={this.humanizeifDefaultGroupName(permissionGroup.group)} + overLayComponent={this.renderPopoverContent} + className="groups-folder-list" + dataCy={this.humanizeifDefaultGroupName(permissionGroup.group) + .toLowerCase() + .replace(/\s+/g, '-')} + > + + {this.humanizeifDefaultGroupName(permissionGroup.group)} + + + ); + })} +
+ +
+ {isLoading ? ( + + ) : ( + + )} +
+
+ )} +
+
+
+ ); + } +} + +export const ManageGroupPermissionsV2 = withTranslation()(ManageGroupPermissionsComponent); + +const Field = ({ + text, + onClick, + customClass, + leftIcon, + leftIconWidth, + leftIconHeight = '18', + leftIconClassName, + buttonDisable = false, + tooltipContent = '', + tooltipId = '', + darkMode = false, +}) => { + return ( +
+ +
+ {leftIcon && ( + + )} +
+
{text}
+
+
+ ); +}; diff --git a/frontend/src/OrganizationSettingsPage/index.jsx b/frontend/src/OrganizationSettingsPage/index.jsx index accdc7bf1d..f40d07df4c 100644 --- a/frontend/src/OrganizationSettingsPage/index.jsx +++ b/frontend/src/OrganizationSettingsPage/index.jsx @@ -17,13 +17,15 @@ export function OrganizationSettings(props) { const { updateSidebarNAV } = useContext(BreadCrumbContext); const { workspaceId } = useParams(); - const sideBarNavs = ['Users', 'Groups', 'Workspace login', 'Workspace variables']; + const sideBarNavs = ['Users', 'Groups', 'Groups V2', 'Workspace login', 'Workspace variables']; const defaultOrgName = (groupName) => { switch (groupName) { case 'users': return 'Users'; case 'groups': return 'Groups'; + case 'groups2': + return 'Groups V2'; case 'workspace-login': return 'Workspace login'; case 'workspace-variables': diff --git a/frontend/src/_components/MultiSelectUser.jsx b/frontend/src/_components/MultiSelectUser.jsx index 525b340087..28773c1a3c 100644 --- a/frontend/src/_components/MultiSelectUser.jsx +++ b/frontend/src/_components/MultiSelectUser.jsx @@ -19,7 +19,7 @@ function MultiSelectUser({ const listOfOptions = useRef([]); useEffect(() => { - setOptions(filterOptions(listOfOptions.current)); + setOptions(listOfOptions.current); // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedValues, listOfOptions.current]); @@ -68,7 +68,7 @@ function MultiSelectUser({ ); return (
- + {/* */} +
{children}
+ + ); + }; + + const MultiValue = (props) => ( + +
{props.data.name}
+
+ ); + + const selectStyles = { + indicatorSeparator: (base) => ({ + ...base, + display: 'none', + }), + option: (base) => ({ + ...base, + '.select-option': { + margin: '0px 10px', + }, + }), + multiValue: (base) => ({ + ...base, + borderRadius: '6px', + backgroundColor: 'var(--slate3)', + color: 'var(--slate11)', + '.selected-value': { + padding: '0px 6px 1px 3px', + color: 'var(--slate11)', + }, + }), + multiValueRemove: (base, state) => ({ + ...base, + '&:hover': { + backgroundColor: 'var(--tomato3)', + color: 'var(--tomato9)', + }, + paddingLeft: '0px', + ...(state.data.isFixed && { display: 'none' }), + }), + input: (base) => ({ + ...base, + input: { + height: '25px !important', + color: 'var(--slate11) !important', + }, + }), + control: (base) => ({ + ...base, + outline: 'none', + border: '1px solid var(--slate7)', + boxShadow: 'none', + borderRadius: '6px', + background: 'unset', + '&:hover': { + border: '1px solid var(--slate8)', + }, + }), + menuList: (base) => ({ + ...base, + maxHeight: '200px', + }), + menu: (base) => ({ + ...base, + background: 'var(--slate1)', + '.add-group-btn': { + display: 'flex', + justifyContent: 'flex-end', + padding: '8px', + borderTop: '1px solid var(--slate5)', + '.create-group': { + background: 'none !important', + '.rectangle-add-icon': { + width: '20px', + height: '20px', + }, + }, + }, + }), + }; + + return ( +