-
+
Share project private key with us?{' '}
diff --git a/apps/platform/src/components/dashboard/project/createProjectDialogue/index.tsx b/apps/platform/src/components/dashboard/project/createProjectDialogue/index.tsx
index ad15f876b..b2dd2c209 100644
--- a/apps/platform/src/components/dashboard/project/createProjectDialogue/index.tsx
+++ b/apps/platform/src/components/dashboard/project/createProjectDialogue/index.tsx
@@ -3,11 +3,11 @@ import { useAtom, useAtomValue } from 'jotai'
import { Plus } from 'lucide-react'
import { AddSVG } from '@public/svg/shared'
import ViewAndDownloadProjectKeysDialog from '../viewAndDownloadKeysDialog'
-import CreateProjectName from './create-project-name'
-import CreateProjectDescription from './create-project-description'
-import CreateProjectAccessLevel from './create-project-access-level'
-import CreateProjectStorePrivateKey from './create-project-store-private-key'
import CreateProjectEnvironmentList from './create-project-environment-list'
+import CreateProjectStorePrivateKey from './create-project-store-private-key'
+import CreateProjectAccessLevel from './create-project-access-level'
+import CreateProjectDescription from './create-project-description'
+import CreateProjectName from './create-project-name'
import { Button } from '@/components/ui/button'
import {
Dialog,
@@ -103,8 +103,9 @@ export default function CreateProjectDialogue(): JSX.Element {
)}
diff --git a/apps/platform/src/components/dashboard/project/exportProjectConfigurations/index.tsx b/apps/platform/src/components/dashboard/project/exportProjectConfigurations/index.tsx
index d19a257b8..1da6b1577 100644
--- a/apps/platform/src/components/dashboard/project/exportProjectConfigurations/index.tsx
+++ b/apps/platform/src/components/dashboard/project/exportProjectConfigurations/index.tsx
@@ -1,6 +1,6 @@
-import ExportProjectFormatInput from './export-project-format-input'
-import ExportProjectEnvironmentInput from './export-project-environment-input'
import ExportProjectPrivateKeyInput from './export-project-private-key-input'
+import ExportProjectEnvironmentInput from './export-project-environment-input'
+import ExportProjectFormatInput from './export-project-format-input'
import {
Dialog,
DialogContent,
diff --git a/apps/platform/src/components/dashboard/secret/addSecretDialogue/index.tsx b/apps/platform/src/components/dashboard/secret/addSecretDialogue/index.tsx
index c5a75eb6f..914376eff 100644
--- a/apps/platform/src/components/dashboard/secret/addSecretDialogue/index.tsx
+++ b/apps/platform/src/components/dashboard/secret/addSecretDialogue/index.tsx
@@ -2,8 +2,6 @@ import React, { useCallback, useState } from 'react'
import { toast } from 'sonner'
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import { AddSVG } from '@public/svg/shared'
-import { Input } from '../../../ui/input'
-import { Button } from '../../../ui/button'
import {
Dialog,
DialogContent,
@@ -12,6 +10,8 @@ import {
DialogTitle,
DialogTrigger
} from '../../../ui/dialog'
+import { Button } from '../../../ui/button'
+import { Input } from '../../../ui/input'
import ControllerInstance from '@/lib/controller-instance'
import {
createSecretOpenAtom,
diff --git a/apps/platform/src/components/dashboard/secret/emptySecretListSection/index.tsx b/apps/platform/src/components/dashboard/secret/emptySecretListSection/index.tsx
index cc73c7596..33bce7977 100644
--- a/apps/platform/src/components/dashboard/secret/emptySecretListSection/index.tsx
+++ b/apps/platform/src/components/dashboard/secret/emptySecretListSection/index.tsx
@@ -23,9 +23,10 @@ export default function EmptySecretListContent(): React.JSX.Element {
diff --git a/apps/platform/src/components/integrations/IntegrationDetails/index.tsx b/apps/platform/src/components/integrations/IntegrationDetails/index.tsx
index 5c99d5193..2f0acf7b4 100644
--- a/apps/platform/src/components/integrations/IntegrationDetails/index.tsx
+++ b/apps/platform/src/components/integrations/IntegrationDetails/index.tsx
@@ -1,7 +1,7 @@
import React, { useCallback } from 'react'
-import { EditTwoSVG, TrashWhiteSVG } from '@public/svg/shared'
import type { Integration } from '@keyshade/schema'
import { useSetAtom } from 'jotai'
+import { EditTwoSVG, TrashWhiteSVG } from '@public/svg/shared'
import IntegrationIcon from '../integrationIcon'
import { formatDate, formatText } from '@/lib/utils'
import { Button } from '@/components/ui/button'
diff --git a/apps/platform/src/components/integrations/createIntegration/index.tsx b/apps/platform/src/components/integrations/createIntegration/index.tsx
index 28f5dc158..9ecfafd69 100644
--- a/apps/platform/src/components/integrations/createIntegration/index.tsx
+++ b/apps/platform/src/components/integrations/createIntegration/index.tsx
@@ -4,8 +4,8 @@ import { useAtomValue, useSetAtom } from 'jotai'
import { ArrowLeftRight, CheckSquare2 } from 'lucide-react'
import { Integrations } from '@keyshade/common'
import { KeyshadeBigSVG } from '@public/svg/auth'
-import IntegrationIcon from '../integrationIcon'
import SetupIntegration from '../integrationSetup'
+import IntegrationIcon from '../integrationIcon'
import { Button } from '@/components/ui/button'
import {
Dialog,
diff --git a/apps/platform/src/components/integrations/integrationList/index.tsx b/apps/platform/src/components/integrations/integrationList/index.tsx
index aa3ae8706..7498794df 100644
--- a/apps/platform/src/components/integrations/integrationList/index.tsx
+++ b/apps/platform/src/components/integrations/integrationList/index.tsx
@@ -2,8 +2,8 @@ import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import React, { useCallback, useEffect, useState } from 'react'
import type { Integration } from '@keyshade/schema'
import { useRouter } from 'next/navigation'
-import IntegrationIcon from '../integrationIcon'
import EmptyIntegration from '../emptyIntegration'
+import IntegrationIcon from '../integrationIcon'
import {
integrationsOfWorkspaceAtom,
selectedIntegrationAtom,
diff --git a/apps/platform/src/components/integrations/integrationServices/index.tsx b/apps/platform/src/components/integrations/integrationServices/index.tsx
index bc6d9362e..b45a5e10d 100644
--- a/apps/platform/src/components/integrations/integrationServices/index.tsx
+++ b/apps/platform/src/components/integrations/integrationServices/index.tsx
@@ -3,8 +3,8 @@ import React, { useCallback, useMemo } from 'react'
import { Integrations } from '@keyshade/common'
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import type { Integration } from '@keyshade/schema'
-import IntegrationIcon from '../integrationIcon'
import CreateIntegration from '../createIntegration'
+import IntegrationIcon from '../integrationIcon'
import { Button } from '@/components/ui/button'
import {
createIntegrationOpenAtom,
diff --git a/apps/platform/src/components/integrations/integrationSetup/index.tsx b/apps/platform/src/components/integrations/integrationSetup/index.tsx
index ff6a378b4..95dcf1afa 100644
--- a/apps/platform/src/components/integrations/integrationSetup/index.tsx
+++ b/apps/platform/src/components/integrations/integrationSetup/index.tsx
@@ -3,8 +3,8 @@ import React, { useState } from 'react'
import type { IntegrationTypeEnum } from '@keyshade/schema'
import { toast } from 'sonner'
import { useSetAtom } from 'jotai'
-import ProjectEnvironmentInput from '../projectEnvironmentInput'
import ProjectEnvironmentSelect from '../projectEnvironmentSelect'
+import ProjectEnvironmentInput from '../projectEnvironmentInput'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import IntegrationMetadata from '@/components/integrations/integrationMetadata'
diff --git a/apps/platform/src/components/integrations/updateIntegrationSheet/index.tsx b/apps/platform/src/components/integrations/updateIntegrationSheet/index.tsx
index b470f2fa4..b704ab097 100644
--- a/apps/platform/src/components/integrations/updateIntegrationSheet/index.tsx
+++ b/apps/platform/src/components/integrations/updateIntegrationSheet/index.tsx
@@ -5,9 +5,9 @@ import { useAtom } from 'jotai'
import type { EventTypeEnum } from '@keyshade/schema'
import type { VercelEnvironmentMapping } from '@keyshade/common'
import { Integrations } from '@keyshade/common'
-import ProjectEnvironmentInput from '../projectEnvironmentInput'
-import UpdateKeyMapping from '../updateKeymapping'
import UpdateEnvironment from '../updateEnvironment'
+import UpdateKeyMapping from '../updateKeymapping'
+import ProjectEnvironmentInput from '../projectEnvironmentInput'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import {
diff --git a/apps/platform/src/components/main/emptyProjectState/index.tsx b/apps/platform/src/components/main/emptyProjectState/index.tsx
index 86a675ed9..9c2a4ebf3 100644
--- a/apps/platform/src/components/main/emptyProjectState/index.tsx
+++ b/apps/platform/src/components/main/emptyProjectState/index.tsx
@@ -1,6 +1,6 @@
-import { FolderIconSVG } from '@public/svg/dashboard'
import { useSetAtom } from 'jotai'
import React from 'react'
+import { FolderIconSVG } from '@public/svg/dashboard'
import { createProjectOpenAtom } from '@/store'
import { Button } from '@/components/ui/button'
diff --git a/apps/platform/src/components/members/memberRow/index.tsx b/apps/platform/src/components/members/memberRow/index.tsx
index 87306c17c..fd7548e0f 100644
--- a/apps/platform/src/components/members/memberRow/index.tsx
+++ b/apps/platform/src/components/members/memberRow/index.tsx
@@ -17,6 +17,7 @@ import {
} from '@/components/ui/tooltip'
import AvatarComponent from '@/components/common/avatar'
import { Button } from '@/components/ui/button'
+import RoleBadge from '@/components/common/role-badge'
function MemberRow({
member,
@@ -74,10 +75,14 @@ function MemberRow({
{dayjs(member.user.joinedOn).format('MMM D, YYYY')}
-
-
- {member.roles[0].role.name}
-
+
+ {member.roles.map((role) => {
+ return (
+
+ {role.role.name}
+
+ )
+ })}
diff --git a/apps/platform/src/components/members/membersHeader/index.tsx b/apps/platform/src/components/members/membersHeader/index.tsx
index 0392015e0..f2a5e2765 100644
--- a/apps/platform/src/components/members/membersHeader/index.tsx
+++ b/apps/platform/src/components/members/membersHeader/index.tsx
@@ -4,6 +4,7 @@ import { ChevronDown } from 'lucide-react'
import { useAtomValue, useSetAtom } from 'jotai'
import { toast } from 'sonner'
import { AddSVG } from '@public/svg/shared'
+import type { WorkspaceMember } from '@keyshade/schema'
import { Button } from '@/components/ui/button'
import {
Dialog,
@@ -22,11 +23,9 @@ import {
} from '@/store'
import { useHttp } from '@/hooks/use-http'
import ControllerInstance from '@/lib/controller-instance'
+import RoleBadge from '@/components/common/role-badge'
-interface SelectedRoles {
- name: string
- roleSlug: string
-}
+type SelectedRoles = WorkspaceMember['roles'][number]['role']
export default function MembersHeader(): React.JSX.Element {
const [email, setEmail] = useState
('')
@@ -44,9 +43,9 @@ export default function MembersHeader(): React.JSX.Element {
const toggleRole = (role: SelectedRoles): void => {
setSelectedRoles((prev) => {
- const isSelected = prev.some((r) => r.roleSlug === role.roleSlug)
+ const isSelected = prev.some((r) => r.slug === role.slug)
if (isSelected) {
- return prev.filter((r) => r.roleSlug !== role.roleSlug)
+ return prev.filter((r) => r.slug !== role.slug)
}
return [...prev, role]
})
@@ -58,7 +57,7 @@ export default function MembersHeader(): React.JSX.Element {
members: [
{
email,
- roleSlugs: selectedRoles.map((role) => role.roleSlug)
+ roleSlugs: selectedRoles.map((role) => role.slug)
}
]
})
@@ -72,7 +71,7 @@ export default function MembersHeader(): React.JSX.Element {
}, [])
const handleInviteMembers = useCallback(async () => {
- if (email.trim() === '') {
+ if (email.length === 0) {
toast.error('Email is required')
return
}
@@ -133,10 +132,11 @@ export default function MembersHeader(): React.JSX.Element {
type="email"
value={email}
/>
+ {/* */}
@@ -159,12 +159,12 @@ export default function MembersHeader(): React.JSX.Element {
) : (
<>
{selectedRoles.slice(0, 2).map((role) => (
-
{role.name}
-
+
))}
{selectedRoles.length > 2 && (
@@ -189,13 +189,17 @@ export default function MembersHeader(): React.JSX.Element {
>
r.roleSlug === role.slug
+ (r) => r.slug === role.slug
)}
className="mr-2 rounded-sm border-none bg-gray-400 data-[state=checked]:border-none data-[state=checked]:bg-white data-[state=checked]:text-black"
onCheckedChange={() =>
toggleRole({
+ id: role.id,
+ colorCode: role.colorCode,
name: role.name,
- roleSlug: role.slug
+ slug: role.slug,
+ description: role.description,
+ authorities: role.authorities
})
}
/>
diff --git a/apps/platform/src/components/roles/createRoleDialog/index.tsx b/apps/platform/src/components/roles/createRoleDialog/index.tsx
index fbb9ed2b1..0f9513ba0 100644
--- a/apps/platform/src/components/roles/createRoleDialog/index.tsx
+++ b/apps/platform/src/components/roles/createRoleDialog/index.tsx
@@ -3,8 +3,8 @@ import React, { useCallback, useState } from 'react'
import type { AuthorityEnum } from '@keyshade/schema'
import { toast } from 'sonner'
import { AddSVG } from '@public/svg/shared'
-import type { ProjectEnvironmentComboType } from '../projectEnvironmentSelector'
import ProjectEnvironmentSelector from '../projectEnvironmentSelector'
+import type { ProjectEnvironmentComboType } from '../projectEnvironmentSelector'
import { Button } from '@/components/ui/button'
import {
Dialog,
diff --git a/apps/platform/src/components/roles/editRoleSheet/index.tsx b/apps/platform/src/components/roles/editRoleSheet/index.tsx
index c78b2542a..e3db5808e 100644
--- a/apps/platform/src/components/roles/editRoleSheet/index.tsx
+++ b/apps/platform/src/components/roles/editRoleSheet/index.tsx
@@ -2,8 +2,8 @@ import { useAtom, useSetAtom } from 'jotai'
import React, { useCallback, useEffect, useState } from 'react'
import type { AuthorityEnum } from '@keyshade/schema'
import { toast } from 'sonner'
-import type { ProjectEnvironmentComboType } from '../projectEnvironmentSelector'
import ProjectEnvironmentSelector from '../projectEnvironmentSelector'
+import type { ProjectEnvironmentComboType } from '../projectEnvironmentSelector'
import { Button } from '@/components/ui/button'
import {
Sheet,
diff --git a/apps/platform/src/components/roles/roleCard/index.tsx b/apps/platform/src/components/roles/roleCard/index.tsx
index 55564cc8f..085dd6138 100644
--- a/apps/platform/src/components/roles/roleCard/index.tsx
+++ b/apps/platform/src/components/roles/roleCard/index.tsx
@@ -1,270 +1,29 @@
-'use client'
-
-import type { AuthorityEnum, WorkspaceRole } from '@keyshade/schema'
-import dayjs from 'dayjs'
-import { Copy, Pen } from 'lucide-react'
-import { useCallback, useState } from 'react'
-import { useSetAtom } from 'jotai'
-import { TrashWhiteSVG } from '@public/svg/shared'
-import { NoteIconSVG } from '@public/svg/secret'
-import AvatarComponent from '@/components/common/avatar'
-import { TableCell, TableRow } from '@/components/ui/table'
-import {
- Tooltip,
- TooltipArrow,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger
-} from '@/components/ui/tooltip'
-import { deleteRoleOpenAtom, editRoleOpenAtom, selectedRoleAtom } from '@/store'
-import { Button } from '@/components/ui/button'
-import { copyToClipboard } from '@/lib/clipboard'
+import type { WorkspaceRole } from '@keyshade/schema'
+import RoleNameCell from './role-name-cell'
+import RoleMembersCell from './role-members-cell'
+import RoleAuthoritiesCell from './role-authorities-cell'
+import RoleProjectEnvironmentCell from './role-project-environment-cell'
+import RoleActionCell from './role-action-cell'
+import { TableRow } from '@/components/ui/table'
interface RoleListItemProps {
role: WorkspaceRole
}
-function AuthorityTile({ authority }: { authority: AuthorityEnum }) {
- const formattedAuthority = authority
- .split('_')
- .map((word) => word.charAt(0) + word.slice(1).toLowerCase())
- .join(' ')
-
- return (
-
- {formattedAuthority}
-
- )
-}
-
-function ProjectsAndEnvironmentsTooltip({
- projectsAndEnvironments
-}: {
- projectsAndEnvironments: WorkspaceRole['projects']
-}) {
- return projectsAndEnvironments.length > 0 ? (
-
- {projectsAndEnvironments.map(({ project, environments }) => (
-
- {project.name}{' '}
- {environments.length > 0
- ? `(${environments.map((env) => env.name).join(', ')})`
- : ''}
-
- ))}
-
- ) : (
-
- No projects and environments associated with this role
-
- )
-}
-
export default function RoleCard({
role
}: RoleListItemProps): React.JSX.Element {
- const AUTHORITY_DISPLAY_LIMIT = 5
- const hasAuthorities = role.authorities.length > 0
-
- const [showAllAuthorities, setShowAllAuthorities] = useState(false)
-
- const setSelectedRole = useSetAtom(selectedRoleAtom)
- const setIsDeleteRoleOpen = useSetAtom(deleteRoleOpenAtom)
- const setIsEditRoleOpen = useSetAtom(editRoleOpenAtom)
-
- const isAuthorisedToEditRole = role.entitlements.canUpdate
- const isAuthorisedToDeleteRole = role.entitlements.canDelete
-
- const handleDeleteRole = useCallback(() => {
- setSelectedRole(role)
- setIsDeleteRoleOpen(true)
- }, [role, setIsDeleteRoleOpen, setSelectedRole])
-
- const handleEditRole = useCallback(() => {
- setSelectedRole(role)
- setIsEditRoleOpen(true)
- }, [role, setIsEditRoleOpen, setSelectedRole])
-
- const isAdminRole = role.authorities.some(
- (authority) => authority === 'WORKSPACE_ADMIN'
- )
-
return (
-
-
-
- {role.name}
- {role.description ? (
-
-
-
-
-
-
- {role.description}
-
-
-
- ) : null}
-
-
-
- {role.members.map((member) => {
- const isInvited = !member.invitationAccepted
- return (
-
-
-
-
-
-
-
-
- {member.name ? (
-
{member.name}
- ) : null}
-
{member.email}
-
-
-
- {isInvited ? 'Invited' : 'Joined'}
-
-
- {dayjs(String(member.memberSince)).format(
- 'MMM D, YYYY'
- )}
-
-
-
-
-
-
- )
- })}
-
-
-
-
- {hasAuthorities ? (
- <>
- {role.authorities
- .slice(0, showAllAuthorities ? role.authorities.length : 5)
- .map((authority) => (
-
- ))}
- {role.authorities.length > AUTHORITY_DISPLAY_LIMIT ? (
-
- ) : null}
- >
- ) : (
-
- No authorities available
-
- )}
-
-
-
-
-
-
- {role.projects.length} projects,{' '}
- {role.projects.reduce((a, b) => a + b.environments.length, 0)}{' '}
- environments
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Copy the role slug to your clipboard.
-
-
-
-
-
-
-
-
-
-
-
- {isAdminRole ? (
-
- You can not delete a workspace admin role
-
-
- ) : null}
-
-
-
+
+
+
+
+
+
)
}
diff --git a/apps/platform/src/components/roles/roleCard/role-action-cell.tsx b/apps/platform/src/components/roles/roleCard/role-action-cell.tsx
new file mode 100644
index 000000000..2df942da4
--- /dev/null
+++ b/apps/platform/src/components/roles/roleCard/role-action-cell.tsx
@@ -0,0 +1,110 @@
+'use client'
+import { TrashWhiteSVG } from '@public/svg/shared'
+import { Copy, Pen } from 'lucide-react'
+import React, { useCallback } from 'react'
+import { useSetAtom } from 'jotai'
+import type { WorkspaceRole } from '@keyshade/schema'
+import { Button } from '@/components/ui/button'
+import { TableCell } from '@/components/ui/table'
+import {
+ Tooltip,
+ TooltipArrow,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger
+} from '@/components/ui/tooltip'
+import { copyToClipboard } from '@/lib/clipboard'
+import { deleteRoleOpenAtom, editRoleOpenAtom, selectedRoleAtom } from '@/store'
+
+interface RoleActionCellProps {
+ role: WorkspaceRole
+}
+
+function RoleActionCell({ role }: RoleActionCellProps) {
+ const setSelectedRole = useSetAtom(selectedRoleAtom)
+ const setIsDeleteRoleOpen = useSetAtom(deleteRoleOpenAtom)
+ const setIsEditRoleOpen = useSetAtom(editRoleOpenAtom)
+
+ const isAuthorisedToEditRole = role.entitlements.canUpdate
+ const isAuthorisedToDeleteRole = role.entitlements.canDelete
+
+ const handleDeleteRole = useCallback(() => {
+ setSelectedRole(role)
+ setIsDeleteRoleOpen(true)
+ }, [role, setIsDeleteRoleOpen, setSelectedRole])
+
+ const handleEditRole = useCallback(() => {
+ setSelectedRole(role)
+ setIsEditRoleOpen(true)
+ }, [role, setIsEditRoleOpen, setSelectedRole])
+
+ const isAdminRole = role.authorities.some(
+ (authority) => authority === 'WORKSPACE_ADMIN'
+ )
+
+ return (
+
+
+
+
+
+
+
+ Copy the role slug to your clipboard.
+
+
+
+
+
+
+
+
+
+
+
+ {isAdminRole ? (
+
+ You can not delete a workspace admin role
+
+
+ ) : null}
+
+
+
+ )
+}
+
+export default RoleActionCell
diff --git a/apps/platform/src/components/roles/roleCard/role-authorities-cell.tsx b/apps/platform/src/components/roles/roleCard/role-authorities-cell.tsx
new file mode 100644
index 000000000..56a8d3ac7
--- /dev/null
+++ b/apps/platform/src/components/roles/roleCard/role-authorities-cell.tsx
@@ -0,0 +1,60 @@
+import React, { useState } from 'react'
+import type { AuthorityEnum, WorkspaceRole } from '@keyshade/schema'
+import { Button } from '@/components/ui/button'
+import { TableCell } from '@/components/ui/table'
+
+function AuthorityTile({ authority }: { authority: AuthorityEnum }) {
+ const formattedAuthority = authority
+ .split('_')
+ .map((word) => word.charAt(0) + word.slice(1).toLowerCase())
+ .join(' ')
+
+ return (
+
+ {formattedAuthority}
+
+ )
+}
+
+interface RoleAuthoritiesCellProps {
+ authorities: WorkspaceRole['authorities']
+}
+
+const AUTHORITY_DISPLAY_LIMIT = 5
+
+function RoleAuthoritiesCell({ authorities }: RoleAuthoritiesCellProps) {
+ const [showAllAuthorities, setShowAllAuthorities] = useState(false)
+ const hasAuthorities = authorities.length > 0
+
+ return (
+
+
+ {hasAuthorities ? (
+ <>
+ {authorities
+ .slice(0, showAllAuthorities ? authorities.length : 5)
+ .map((authority) => (
+
+ ))}
+ {authorities.length > AUTHORITY_DISPLAY_LIMIT ? (
+
+ ) : null}
+ >
+ ) : (
+
+ No authorities available
+
+ )}
+
+
+ )
+}
+
+export default RoleAuthoritiesCell
diff --git a/apps/platform/src/components/roles/roleCard/role-members-cell.tsx b/apps/platform/src/components/roles/roleCard/role-members-cell.tsx
new file mode 100644
index 000000000..37d980063
--- /dev/null
+++ b/apps/platform/src/components/roles/roleCard/role-members-cell.tsx
@@ -0,0 +1,68 @@
+import dayjs from 'dayjs'
+import React from 'react'
+import type { WorkspaceRole } from '@keyshade/schema'
+import AvatarComponent from '@/components/common/avatar'
+import { TableCell } from '@/components/ui/table'
+import {
+ Tooltip,
+ TooltipArrow,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger
+} from '@/components/ui/tooltip'
+
+interface RoleMembersCellProps {
+ members: WorkspaceRole['members']
+}
+
+function RoleMembersCell({ members }: RoleMembersCellProps) {
+ return (
+
+
+ {members.map((member) => {
+ const isInvited = !member.invitationAccepted
+ return (
+
+
+
+
+
+
+
+
+ {member.name ? (
+
{member.name}
+ ) : null}
+
{member.email}
+
+
+
+ {isInvited ? 'Invited' : 'Joined'}
+
+
+ {dayjs(String(member.memberSince)).format('MMM D, YYYY')}
+
+
+
+
+
+
+ )
+ })}
+
+
+ )
+}
+
+export default RoleMembersCell
diff --git a/apps/platform/src/components/roles/roleCard/role-name-cell.tsx b/apps/platform/src/components/roles/roleCard/role-name-cell.tsx
new file mode 100644
index 000000000..fd03e332c
--- /dev/null
+++ b/apps/platform/src/components/roles/roleCard/role-name-cell.tsx
@@ -0,0 +1,40 @@
+import { PermissionBadgeSVG } from '@public/svg/roles'
+import { NoteIconSVG } from '@public/svg/secret'
+import React from 'react'
+import type { WorkspaceRole } from '@keyshade/schema'
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger
+} from '@/components/ui/tooltip'
+import { TableCell } from '@/components/ui/table'
+
+interface RoleNameCellProps {
+ colorCode: WorkspaceRole['colorCode']
+ name: WorkspaceRole['name']
+ description?: WorkspaceRole['description']
+}
+
+function RoleNameCell({ colorCode, name, description }: RoleNameCellProps) {
+ return (
+
+
+ {name}
+ {description ? (
+
+
+
+
+
+
+ {description}
+
+
+
+ ) : null}
+
+ )
+}
+
+export default RoleNameCell
diff --git a/apps/platform/src/components/roles/roleCard/role-project-environment-cell.tsx b/apps/platform/src/components/roles/roleCard/role-project-environment-cell.tsx
new file mode 100644
index 000000000..fdb99fbf2
--- /dev/null
+++ b/apps/platform/src/components/roles/roleCard/role-project-environment-cell.tsx
@@ -0,0 +1,66 @@
+import React from 'react'
+import type { WorkspaceRole } from '@keyshade/schema'
+import { TableCell } from '@/components/ui/table'
+import {
+ Tooltip,
+ TooltipArrow,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger
+} from '@/components/ui/tooltip'
+
+function ProjectsAndEnvironmentsTooltip({
+ projectsAndEnvironments
+}: {
+ projectsAndEnvironments: WorkspaceRole['projects']
+}) {
+ return projectsAndEnvironments.length > 0 ? (
+
+ {projectsAndEnvironments.map(({ project, environments }) => (
+
+ {project.name}{' '}
+ {environments.length > 0
+ ? `(${environments.map((env) => env.name).join(', ')})`
+ : ''}
+
+ ))}
+
+ ) : (
+
+ No projects and environments associated with this role
+
+ )
+}
+
+interface RoleProjectEnvironmentCellProps {
+ projects: WorkspaceRole['projects']
+}
+
+function RoleProjectEnvironmentCell({
+ projects
+}: RoleProjectEnvironmentCellProps) {
+ return (
+
+
+
+
+ {projects.length} projects,{' '}
+ {projects.reduce((a, b) => a + b.environments.length, 0)}{' '}
+ environments
+
+
+
+
+
+
+
+
+ )
+}
+
+export default RoleProjectEnvironmentCell
diff --git a/apps/platform/src/components/roles/rolesList/index.tsx b/apps/platform/src/components/roles/rolesList/index.tsx
index 508e9017e..e7a4f94fb 100644
--- a/apps/platform/src/components/roles/rolesList/index.tsx
+++ b/apps/platform/src/components/roles/rolesList/index.tsx
@@ -15,7 +15,7 @@ import ErrorCard from '@/components/shared/error-card'
function RoleListItemSkeleton(): React.JSX.Element {
return (
-
+
diff --git a/apps/platform/src/components/shared/add-workspace-dialog.tsx b/apps/platform/src/components/shared/add-workspace-dialog.tsx
index bd20bcbcf..773af450c 100644
--- a/apps/platform/src/components/shared/add-workspace-dialog.tsx
+++ b/apps/platform/src/components/shared/add-workspace-dialog.tsx
@@ -14,13 +14,13 @@ import {
import { Button } from '../ui/button'
import { Input } from '../ui/input'
import { Label } from '../ui/label'
+import { useHttp } from '@/hooks/use-http'
+import ControllerInstance from '@/lib/controller-instance'
import {
allWorkspacesAtom,
selectedWorkspaceAtom,
globalSearchDataAtom
} from '@/store'
-import ControllerInstance from '@/lib/controller-instance'
-import { useHttp } from '@/hooks/use-http'
export interface AddWorkspaceDialogProps {
trigger?: React.ReactNode
diff --git a/apps/platform/src/components/shared/navbar/index.tsx b/apps/platform/src/components/shared/navbar/index.tsx
index f93769d28..2b66cfeed 100644
--- a/apps/platform/src/components/shared/navbar/index.tsx
+++ b/apps/platform/src/components/shared/navbar/index.tsx
@@ -11,7 +11,7 @@ function Navbar(): React.JSX.Element {
return (
<>
-