diff --git a/src/components/d-member/DNamespaceMember.stories.tsx b/src/components/d-member/DNamespaceMember.stories.tsx index 64a50966c..b9d0cb568 100644 --- a/src/components/d-member/DNamespaceMember.stories.tsx +++ b/src/components/d-member/DNamespaceMember.stories.tsx @@ -50,7 +50,8 @@ export const MemberListExample = () => { }] }, userAbilities: { - deleteMember: true + deleteMember: true, + assignMemberRoles: true } }) ]) diff --git a/src/components/d-member/DNamespaceMemberCard.tsx b/src/components/d-member/DNamespaceMemberCard.tsx index 719b09049..9258e1570 100644 --- a/src/components/d-member/DNamespaceMemberCard.tsx +++ b/src/components/d-member/DNamespaceMemberCard.tsx @@ -3,11 +3,12 @@ import {Card} from "../card/Card"; import React from "react"; import {DNamespaceMemberContent} from "./DNamespaceMemberContent"; import {DNamespaceMemberView} from "./DNamespaceMember.view"; +import {DNamespaceRoleView} from "../d-role"; export interface DNamespaceMemberCardProps { memberId: NamespaceMember["id"] onRemove?: (member: DNamespaceMemberView) => void - onAssignRole?: (member: DNamespaceMemberView) => void + onAssignRole?: (member: DNamespaceMemberView, roles: DNamespaceRoleView[]) => void } export const DNamespaceMemberCard: React.FC = (props) => { diff --git a/src/components/d-member/DNamespaceMemberContent.tsx b/src/components/d-member/DNamespaceMemberContent.tsx index b6e03fac5..2ebd035cb 100644 --- a/src/components/d-member/DNamespaceMemberContent.tsx +++ b/src/components/d-member/DNamespaceMemberContent.tsx @@ -1,24 +1,27 @@ -import React from "react"; -import {Flex} from "../flex/Flex"; -import {NamespaceMember} from "@code0-tech/sagittarius-graphql-types"; -import {useService, useStore} from "../../utils"; -import {DNamespaceMemberReactiveService} from "./DNamespaceMember.service"; -import {DUserReactiveService} from "../d-user"; -import {DNamespaceRoleReactiveService} from "../d-role"; -import {Avatar} from "../avatar/Avatar"; -import {Text} from "../text/Text"; -import {Badge} from "../badge/Badge"; -import {IconDots, IconMailCheck, IconUserCog, IconUserOff} from "@tabler/icons-react"; -import {Button} from "../button/Button"; -import {Tooltip, TooltipArrow, TooltipContent, TooltipPortal, TooltipTrigger} from "../tooltip/Tooltip"; -import {DNamespaceRolePermissions} from "../d-role/DNamespaceRolePermissions"; -import {Menu, MenuContent, MenuItem, MenuLabel, MenuPortal, MenuTrigger} from "../menu/Menu"; -import {DNamespaceMemberView} from "./DNamespaceMember.view"; +import React from "react" +import {Flex} from "../flex/Flex" +import {NamespaceMember} from "@code0-tech/sagittarius-graphql-types" +import {useService, useStore} from "../../utils" +import {DNamespaceMemberReactiveService} from "./DNamespaceMember.service" +import {DUserReactiveService} from "../d-user" +import {DNamespaceRoleReactiveService, DNamespaceRoleView} from "../d-role" +import {Avatar} from "../avatar/Avatar" +import {Text} from "../text/Text" +import {Badge} from "../badge/Badge" +import {IconDots, IconMailCheck, IconTrash, IconUserCog, IconUserOff} from "@tabler/icons-react" +import {Button} from "../button/Button" +import {Tooltip, TooltipArrow, TooltipContent, TooltipPortal, TooltipTrigger} from "../tooltip/Tooltip" +import {DNamespaceRolePermissions} from "../d-role/DNamespaceRolePermissions" +import {Menu, MenuContent, MenuItem, MenuLabel, MenuPortal, MenuSeparator, MenuTrigger} from "../menu/Menu" +import {DNamespaceMemberView} from "./DNamespaceMember.view" +import {Dialog, DialogClose, DialogContent, DialogPortal} from "../dialog/Dialog" +import {Card} from "../card/Card" +import CardSection from "../card/CardSection" export interface DNamespaceMemberContentProps { memberId: NamespaceMember['id'] onRemove?: (member: DNamespaceMemberView) => void - onAssignRole?: (member: DNamespaceMemberView) => void + onAssignRole?: (member: DNamespaceMemberView, roles: DNamespaceRoleView[]) => void } export const DNamespaceMemberContent: React.FC = (props) => { @@ -35,8 +38,92 @@ export const DNamespaceMemberContent: React.FC = ( const member = React.useMemo(() => memberService.getById(memberId), [memberStore, memberId]) const user = React.useMemo(() => userService.getById(member?.user?.id), [userStore, member]) const assignedRoles = React.useMemo(() => member?.roles?.nodes?.map(role => roleService.getById(role?.id, {namespaceId: member?.namespace?.id})) || [], [roleStore, member]) + const [localAssignedRoles, setLocalAssignedRoles] = React.useState(assignedRoles) + const [openRemovedMemberDialog, setOpenRemovedMemberDialog] = React.useState(false) + const [openAssignRolesDialog, setOpenAssignRolesDialog] = React.useState(false) + const rolesToAssign = roleService + .values({namespaceId: member?.namespace?.id}) + .filter(role => !localAssignedRoles.find(aRole => aRole?.id === role.id)) return + setOpenRemovedMemberDialog(open)}> + + + + Are you sure you want to remove {" "} + + @{user?.username} + {" "} + from the namespace members? + + + + + + + + + + + setOpenAssignRolesDialog(open)}> + + + Assign, remove and manage the roles of a active + member + + {localAssignedRoles.map(role => { + return + + + {role?.name} + + + + + + + })} + + + + + + + + + Roles to add + {rolesToAssign.map((role, index) => { + return <> + { + setLocalAssignedRoles(prevState => [...prevState, role]) + }}> + + {role?.name} + + + + {index < rolesToAssign.length - 1 && } + + })} + + + + + + + + + + + + + + @@ -96,13 +183,13 @@ export const DNamespaceMemberContent: React.FC = ( Actions {member?.userAbilities?.deleteMember && ( - onRemove(member)}> + setOpenRemovedMemberDialog(true)}> Remove member )} {member?.userAbilities?.assignMemberRoles && ( - onAssignRole(member)}> + setOpenAssignRolesDialog(true)}> Assign role diff --git a/src/components/d-member/DNamespaceMemberList.tsx b/src/components/d-member/DNamespaceMemberList.tsx index e64cd9a2c..604d8d96a 100644 --- a/src/components/d-member/DNamespaceMemberList.tsx +++ b/src/components/d-member/DNamespaceMemberList.tsx @@ -8,12 +8,13 @@ import {Card} from "../card/Card"; import CardSection from "../card/CardSection"; import {DNamespaceMemberView} from "./DNamespaceMember.view"; import {DNamespaceMemberContent} from "./DNamespaceMemberContent"; +import {DNamespaceRoleView} from "../d-role"; export interface DNamespaceMemberListProps extends Omit { namespaceId: Namespace["id"] filter?: (runtime: DNamespaceMemberView, index: number) => boolean onRemove?: (member: DNamespaceMemberView) => void - onAssignRole?: (member: DNamespaceMemberView) => void + onAssignRole?: (member: DNamespaceMemberView, roles: DNamespaceRoleView[]) => void } export const DNamespaceMemberList: React.FC = (props) => { diff --git a/src/components/dialog/Dialog.style.scss b/src/components/dialog/Dialog.style.scss index cdcdd24b9..6ad146aa1 100644 --- a/src/components/dialog/Dialog.style.scss +++ b/src/components/dialog/Dialog.style.scss @@ -5,9 +5,6 @@ @use "sass:color"; .dialog { - @include box.box(variables.$primary, variables.$primary, variables.$secondary); - @include helpers.borderRadius(); - backdrop-filter: none; -webkit-backdrop-filter: none; @@ -26,10 +23,13 @@ bottom: 0; left: 0; z-index: 50; - background: rgba(0, 0, 0, 0.5); + background: rgba(variables.$primary, 0.75); } &__content { + @include box.box(variables.$secondary); + @include helpers.borderRadius(); + position: fixed; top: 50%; left: 50%; @@ -39,15 +39,10 @@ max-width: calc(100% - 2rem); gap: 1rem; transform: translate(-50%, -50%); - border: 1px solid helpers.borderColor(); padding: 1rem; - background: variables.$primary; - color: variables.$secondary; - - @include helpers.borderRadius(); @include media.respond-above(md) { - width: 420px; + width: 490px; } } @@ -87,38 +82,4 @@ justify-content: flex-end; } } - - &__close { - position: absolute; - top: 1rem; - right: 1rem; - border-radius: 0.125rem; - border: none; - opacity: 0.7; - transition: opacity 0.2s ease; - background: none; - color: variables.$secondary; - - &:hover { - opacity: 1; - } - - &:focus { - outline: none; - } - - &:disabled { - pointer-events: none; - } - - svg { - pointer-events: none; - flex-shrink: 0; - } - - svg:not([class*="size-"]) { - width: 1rem; - height: 1rem; - } - } } \ No newline at end of file diff --git a/src/components/dialog/Dialog.tsx b/src/components/dialog/Dialog.tsx index c35b3dfd8..b780efd6f 100644 --- a/src/components/dialog/Dialog.tsx +++ b/src/components/dialog/Dialog.tsx @@ -1,9 +1,12 @@ -import * as DialogPrimitive from "@radix-ui/react-dialog" -import {Code0Component, Code0ComponentProps} from "../../utils/types"; -import React, {useEffect} from "react"; -import {mergeCode0Props} from "../../utils/utils"; +import * as DialogPrimitive from "@radix-ui/react-dialog" +import {Code0Component, Code0ComponentProps} from "../../utils"; +import React from "react"; +import {mergeCode0Props} from "../../utils"; import {IconX} from "@tabler/icons-react" import "./Dialog.style.scss" +import {Button} from "../button/Button"; +import {Flex} from "../flex/Flex"; +import {Text} from "../text/Text"; export type DialogProps = Code0ComponentProps & React.ComponentProps export type DialogTriggerProps = Code0ComponentProps & React.ComponentProps @@ -16,6 +19,7 @@ export type DialogHeaderProps = Code0ComponentProps & React.ComponentProps<"div" export type DialogFooterProps = Code0ComponentProps & React.ComponentProps<"div"> export type DialogContentProps = Code0ComponentProps & React.ComponentProps & { showCloseButton?: boolean + title?: string } export type DialogStickyContentProps = Code0Component & { @@ -48,9 +52,14 @@ export const DialogContent: React.FC = (props) => { {props.showCloseButton && ( - - - + + {props.title} + + + + )} {props.children}