-
Notifications
You must be signed in to change notification settings - Fork 3
Import members feature for Workspace and MCP creation #265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 26 commits
23c23d7
0c01a1a
6b440c0
72ab035
d2ce22a
166f647
4a4dcc3
2931141
590a1fb
9b833dc
db1afff
421477e
ba36f94
74b192d
402c410
ccdd7a5
78a6fab
0ae01d9
3dd5531
6044067
781b873
f62e443
9511fdd
4100f11
da3fdec
e4b7dd4
63f7c3c
0a17041
b47494d
d4d3401
3aa41c9
503af2a
e8b65f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,36 +1,46 @@ | ||
| import { FC, useCallback, useState } from 'react'; | ||
| import { FC, useCallback, useMemo, useState } from 'react'; | ||
| import { Button, FlexBox } from '@ui5/webcomponents-react'; | ||
| import { MemberTable } from './MemberTable.tsx'; | ||
| import { Member } from '../../lib/api/types/shared/members'; | ||
| import { useTranslation } from 'react-i18next'; | ||
| import styles from './Members.module.css'; | ||
| import { RadioButtonsSelectOption } from '../Ui/RadioButtonsSelect/RadioButtonsSelect.tsx'; | ||
| import { AddEditMemberDialog } from './AddEditMemberDialog.tsx'; | ||
| import { ImportMembersDialog } from './ImportMembersDialog.tsx'; | ||
|
|
||
| export interface EditMembersProps { | ||
| members: Member[]; | ||
| onMemberChanged: (members: Member[]) => void; | ||
| isValidationError?: boolean; | ||
| requireAtLeastOneMember?: boolean; | ||
| projectName?: string; | ||
| workspaceName?: string; | ||
| type: 'workspace' | 'project' | 'mcp'; | ||
| } | ||
|
|
||
| export const ACCOUNT_TYPES: RadioButtonsSelectOption[] = [ | ||
| { value: 'User', label: 'User Account', icon: 'employee' }, | ||
| { value: 'User', label: 'User', icon: 'employee' }, | ||
| { value: 'ServiceAccount', label: 'Service Account', icon: 'machine' }, | ||
| ]; | ||
|
|
||
| export type AccountType = 'User' | 'ServiceAccount'; | ||
|
|
||
| const removeProjectPrefix = (name?: string) => (name?.startsWith('project-') ? name.slice('project-'.length) : name); | ||
|
|
||
| export const EditMembers: FC<EditMembersProps> = ({ | ||
| members, | ||
| onMemberChanged, | ||
| isValidationError = false, | ||
| requireAtLeastOneMember = true, | ||
| workspaceName, | ||
| projectName, | ||
| type, | ||
| }) => { | ||
| const { t } = useTranslation(); | ||
|
|
||
| const [isMemberDialogOpen, setIsMemberDialogOpen] = useState(false); | ||
| const [memberToEdit, setMemberToEdit] = useState<Member | undefined>(undefined); | ||
| const [isImportDialogOpen, setIsImportDialogOpen] = useState(false); | ||
|
|
||
| const handleRemoveMember = useCallback( | ||
| (email: string) => { | ||
|
|
@@ -53,6 +63,26 @@ export const EditMembers: FC<EditMembersProps> = ({ | |
| setIsMemberDialogOpen(false); | ||
| }, []); | ||
|
|
||
| const handleOpenImportDialog = useCallback(() => { | ||
| setIsImportDialogOpen(true); | ||
| }, []); | ||
|
|
||
| const handleCloseImportDialog = useCallback(() => { | ||
| setIsImportDialogOpen(false); | ||
| }, []); | ||
|
|
||
| const handleImportMembers = useCallback( | ||
| (imported: Member[]) => { | ||
| const byName = new Map<string, Member>(); | ||
| members.forEach((m) => byName.set(m.name, m)); | ||
| imported.forEach((m) => byName.set(m.name, m)); | ||
| const merged = Array.from(byName.values()); | ||
| onMemberChanged(merged); | ||
| setIsImportDialogOpen(false); | ||
| }, | ||
| [members, onMemberChanged], | ||
| ); | ||
|
|
||
| const handleSaveMember = useCallback( | ||
| (member: Member, isEdit: boolean) => { | ||
| let updatedMembers: Member[]; | ||
|
|
@@ -74,17 +104,34 @@ export const EditMembers: FC<EditMembersProps> = ({ | |
| [members, onMemberChanged, memberToEdit], | ||
| ); | ||
|
|
||
| const computedProjectName = useMemo( | ||
| () => (type === 'mcp' ? removeProjectPrefix(projectName) : projectName), | ||
| [type, projectName], | ||
| ); | ||
|
|
||
| return ( | ||
| <FlexBox direction="Column" gap={8}> | ||
| <Button | ||
| className={styles.addButton} | ||
| data-testid="add-member-button" | ||
| design="Emphasized" | ||
| icon={'sap-icon://add-employee'} | ||
| onClick={handleOpenMemberFormDialog} | ||
| > | ||
| {t('EditMembers.addButton')} | ||
| </Button> | ||
| <FlexBox gap={8} justifyContent="SpaceBetween"> | ||
| <Button | ||
| className={styles.addButton} | ||
| data-testid="add-member-button" | ||
| design="Emphasized" | ||
| icon={'sap-icon://add-employee'} | ||
| onClick={handleOpenMemberFormDialog} | ||
| > | ||
| {t('EditMembers.addButton')} | ||
| </Button> | ||
| {type !== 'project' && ( | ||
| <Button | ||
| className={styles.narrowButton} | ||
| data-testid="import-members-button" | ||
| icon={'cause'} | ||
| onClick={handleOpenImportDialog} | ||
| > | ||
| {t('ImportMembersDialog.dialogTitle')} | ||
| </Button> | ||
| )} | ||
| </FlexBox> | ||
| <AddEditMemberDialog | ||
| open={isMemberDialogOpen} | ||
| existingMembers={members} | ||
|
|
@@ -93,6 +140,14 @@ export const EditMembers: FC<EditMembersProps> = ({ | |
| onSave={handleSaveMember} | ||
| /> | ||
|
|
||
| <ImportMembersDialog | ||
| open={isImportDialogOpen} | ||
| workspaceName={workspaceName} | ||
|
||
| projectName={computedProjectName} | ||
| onClose={handleCloseImportDialog} | ||
| onImport={handleImportMembers} | ||
| /> | ||
|
|
||
| <MemberTable | ||
| requireAtLeastOneMember={requireAtLeastOneMember} | ||
| members={members} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| .dialog { | ||
| min-width: 650px; | ||
| } | ||
|
|
||
| .table { | ||
| width: 100%; | ||
| max-height: 400px; | ||
| overflow-y: auto; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.