From 82519f2f68d7f60f03f8168ee6e76e83a01fcd4f Mon Sep 17 00:00:00 2001 From: kyle-ssg Date: Tue, 5 Nov 2024 13:53:48 +0000 Subject: [PATCH] Add tag based permissions ui --- frontend/common/services/useRole.ts | 6 ++++ frontend/web/components/EditPermissions.tsx | 36 ++++++++++++++++--- frontend/web/components/PermissionsTabs.tsx | 7 ++-- .../web/components/RolePermissionsList.tsx | 8 +++-- .../web/components/TagBasedPermissions.tsx | 5 +-- frontend/web/components/modals/CreateRole.tsx | 28 ++++++++++++++- frontend/web/styles/components/_panel.scss | 4 ++- 7 files changed, 80 insertions(+), 14 deletions(-) diff --git a/frontend/common/services/useRole.ts b/frontend/common/services/useRole.ts index 8356d2ef215b..d59a4e1c53b5 100644 --- a/frontend/common/services/useRole.ts +++ b/frontend/common/services/useRole.ts @@ -26,6 +26,12 @@ export const roleService = service query: (query: Req['getRole']) => ({ url: `organisations/${query.organisation_id}/roles/${query.role_id}/`, }), + transformResponse: async (res: Role) => { + return { + ...res, + tag_based: true, + } + }, }), getRoles: builder.query({ providesTags: [{ id: 'LIST', type: 'Role' }], diff --git a/frontend/web/components/EditPermissions.tsx b/frontend/web/components/EditPermissions.tsx index 5993510e5910..e9af028f82a7 100644 --- a/frontend/web/components/EditPermissions.tsx +++ b/frontend/web/components/EditPermissions.tsx @@ -1,4 +1,11 @@ -import React, { FC, forwardRef, useCallback, useEffect, useState } from 'react' +import React, { + FC, + forwardRef, + useCallback, + useEffect, + useMemo, + useState, +} from 'react' import { find } from 'lodash' import { close as closeIcon } from 'ionicons/icons' import { IonIcon } from '@ionic/react' @@ -61,6 +68,7 @@ import classNames from 'classnames' import OrganisationProvider from 'common/providers/OrganisationProvider' import { useHasPermission } from 'common/providers/Permission' import PlanBasedAccess from './PlanBasedAccess' +import { useGetTagsQuery } from 'common/services/useTag' const Project = require('common/project') @@ -166,6 +174,14 @@ const _EditPermissionsModal: FC = withAdminPermissions( ? props.parentId : undefined + const { data: tags, isLoading: tagsLoading } = useGetTagsQuery( + { projectId: `${projectId}` }, + { skip: !role?.tag_based || !projectId }, + ) + const hasTags = useMemo(() => { + return tags?.find((v) => role?.tags.includes(v.id)) + }, [tags, role?.tags]) + const [permissionWasCreated, setPermissionWasCreated] = useState(false) const [rolesSelected, setRolesSelected] = useState< @@ -673,8 +689,16 @@ const _EditPermissionsModal: FC = withAdminPermissions( } const rolesAdded = getRoles(roles, rolesSelected || []) - const isAdmin = admin() + const levelUpperCase = level.toUpperCase() + + if (role?.tag_based && !hasTags) { + return ( +
+ Please add at least one tag to set permissions +
+ ) + } return !permissions || !entityPermissions ? (
@@ -684,7 +708,7 @@ const _EditPermissionsModal: FC = withAdminPermissions(
- {level !== 'organisation' && ( + {level !== 'organisation' && !role?.tag_based && (
@@ -710,9 +734,11 @@ const _EditPermissionsModal: FC = withAdminPermissions( }} title='Permissions' className='no-pad mb-2' - items={permissions} + items={permissions?.filter((item) => { + if (item.key === `VIEW_${levelUpperCase}`) return true + return !(role?.tag_based && !item.supports_tag) + })} renderRow={(p: AvailablePermission) => { - const levelUpperCase = level.toUpperCase() const disabled = level !== 'organisation' && p.key !== `VIEW_${levelUpperCase}` && diff --git a/frontend/web/components/PermissionsTabs.tsx b/frontend/web/components/PermissionsTabs.tsx index 7859d47444ee..8d9f8f81bfe0 100644 --- a/frontend/web/components/PermissionsTabs.tsx +++ b/frontend/web/components/PermissionsTabs.tsx @@ -86,7 +86,7 @@ const PermissionsTabs: FC = ({ theme='pill m-0' isRoles={true} > - {role?.tag_based !== false && ( + {role?.tag_based !== true && ( Organisation @@ -155,8 +155,9 @@ const PermissionsTabs: FC = ({ value={project} />
- - +
+ +
{environments.length > 0 && ( = ({ } const RolePermissionsList: React.FC = forwardRef( - ({ filter, group, level, mainItems, orgId, role, user }, ref) => { + ({ filter, group, level, mainItems, orgId, projectId, role, user }, ref) => { const [expandedItems, setExpandedItems] = useState<(string | number)[]>([]) const mainItemsFiltered = @@ -171,7 +175,7 @@ const RolePermissionsList: React.FC = forwardRef(
)} items={mainItemsFiltered || []} - className='no-pad' + className='no-pad overflow-visible' /> ) }, diff --git a/frontend/web/components/TagBasedPermissions.tsx b/frontend/web/components/TagBasedPermissions.tsx index 2c41545263fb..322de87e67c9 100644 --- a/frontend/web/components/TagBasedPermissions.tsx +++ b/frontend/web/components/TagBasedPermissions.tsx @@ -26,8 +26,6 @@ const TagBasedPermissions: FC = ({ { skip: !projectId || !role }, ) const showTagBasedPermissions = projectId && tag_based_permissions && !!role - const [tagBasedPermissionsEnabled, setTagBasedPermissionsEnabled] = - useState(!!role?.tags?.length) const matchingTags = useMemo(() => { if (!role?.tags || !tags?.length) return [] return role.tags.filter((id) => tags?.find((tag) => tag.id === id)) @@ -37,6 +35,9 @@ const TagBasedPermissions: FC = ({ <> {role?.tag_based && (
+
+ Enable permissions for the following tags: +
Promise @@ -87,6 +88,8 @@ const CreateRole: FC = ({ user: number }[] >([]) + + const [tagBased, setTagBased] = useState(!!role?.tag_based) const [groupSelected, setGroupSelected] = useState< { group: number @@ -309,6 +312,7 @@ const CreateRole: FC = ({ ) useEffect(() => { if (!isLoading && isEdit && roleData) { + setTagBased(roleData.tag_based) setRoleName(roleData.name) setRoleDesc(roleData.description || '') } @@ -331,7 +335,7 @@ const CreateRole: FC = ({ if (!organisationId) return if (isEdit && role) { editRole({ - body: { description: roleDesc, name: roleName }, + body: { description: roleDesc, name: roleName, tag_based: tagBased }, organisation_id: role.organisation, role_id: role.id, }) @@ -340,6 +344,7 @@ const CreateRole: FC = ({ description: roleDesc, name: roleName, organisation_id: organisationId, + tag_based: tagBased, }) } } @@ -365,6 +370,27 @@ const CreateRole: FC = ({ id='roleName' placeholder='E.g. Viewers' /> + + } + unsaved={isEdit && roleDescChanged} + onChange={(event: InputEvent) => { + setRoleDescChanged(true) + setRoleDesc(Utils.safeParseEventValue(event)) + }} + id='description' + placeholder='E.g. Some role description' + /> .panel-content { + overflow: visible; +} .dark { .panel { .icon {