-
Notifications
You must be signed in to change notification settings - Fork 6
Feat: remove team member #342
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 | ||||
|---|---|---|---|---|---|---|
|
|
@@ -67,6 +67,11 @@ | |||||
| "roles": { | ||||||
| "Read": "Reader", | ||||||
| "Write": "Writer" | ||||||
| }, | ||||||
| "removeMemberConfirmationTitle": "Remove member", | ||||||
| "removeMemberConfirmationBody": "Are you sure you want to remove user from the team?", | ||||||
| "ContextMenu": { | ||||||
|
||||||
| "ContextMenu": { | |
| "contextMenu": { |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,100 @@ | ||||||||||||||||||||||
| <template> | ||||||||||||||||||||||
| <button | ||||||||||||||||||||||
| ref="triggerButton" | ||||||||||||||||||||||
| class="more-actions-button" | ||||||||||||||||||||||
|
||||||||||||||||||||||
| class="more-actions-button" | |
| class="more-actions-button" | |
| type="button" | |
| :aria-label="t('noteSettings.team.moreActions')" | |
| :title="t('noteSettings.team.moreActions')" |
Copilot
AI
Feb 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MoreActions is instantiated per team member row, but it calls useNoteSettings(), which creates its own composable state (noteSettings refs, parentNote refs, router, etc.) per instance. This is unnecessary overhead and can lead to duplicated state; consider passing removeMemberByUserId down from the parent, or extracting a lighter-weight service call that doesn't allocate the full composable state for each row.
Copilot
AI
Feb 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This callback triggers the async removal flow but does not await or handle errors from handleRemove(). If removeMemberByUserId throws (network/403/etc.), this can become an unhandled promise rejection and the user gets no feedback. Please make the activation path handle the promise (e.g., mark onActivate async and await, or attach a .catch that shows an error).
| onActivate: () => { | |
| handleRemove(props.teamMember); | |
| hide(); | |
| onActivate: async () => { | |
| hide(); | |
| try { | |
| await handleRemove(props.teamMember); | |
| } catch (error) { | |
| console.error('Failed to remove team member', error); | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,11 @@ | |
| :note-id="noteId" | ||
| :team-member="member" | ||
| /> | ||
| <MoreActions | ||
| :note-id="noteId" | ||
| :team-member="member" | ||
| @team-member-removed="handleMemberRemoved" | ||
| /> | ||
|
Comment on lines
+18
to
+22
|
||
| </template> | ||
|
|
||
| <template #left> | ||
|
|
@@ -40,6 +45,7 @@ import { Section, Row, Avatar } from '@codexteam/ui/vue'; | |
| import RoleSelect from './RoleSelect.vue'; | ||
| import { useI18n } from 'vue-i18n'; | ||
| import useNote from '@/application/services/useNote.ts'; | ||
| import MoreActions from './MoreActions.vue'; | ||
|
|
||
| const props = defineProps<{ | ||
| /** | ||
|
|
@@ -52,6 +58,10 @@ const props = defineProps<{ | |
| noteId: NoteId; | ||
| }>(); | ||
|
|
||
| const emit = defineEmits<{ | ||
| teamMemberRemoved: []; | ||
| }>(); | ||
|
|
||
| const { t } = useI18n(); | ||
| const { note } = useNote({ id: props.noteId }); | ||
|
|
||
|
|
@@ -79,6 +89,11 @@ const sortedTeam = computed(() => { | |
| return roleOrder[a.role] - roleOrder[b.role]; | ||
| }); | ||
| }); | ||
|
|
||
| // Listen for teamMemberRemoved event from child component and bubble them up | ||
| const handleMemberRemoved = () => { | ||
| emit('teamMemberRemoved'); | ||
| }; | ||
| </script> | ||
|
|
||
| <style scoped> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,6 +73,7 @@ | |
| <Team | ||
| :note-id="id" | ||
| :team="noteSettings.team" | ||
| @team-member-removed="handleTeamMemberRemoved" | ||
| /> | ||
| <InviteLink | ||
| :id="props.id" | ||
|
|
@@ -221,6 +222,13 @@ onMounted(async () => { | |
| parentURL.value = getParentURL(parentNote.value?.id); | ||
| }); | ||
|
|
||
| /** | ||
| * Handle team member removal by refreshing the note settings | ||
| */ | ||
| async function handleTeamMemberRemoved() { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think that instead of reloading the page completely we could just update noteSettings composable then we would need to handle boolean that is returned by the api endpoint |
||
| await loadSettings(props.id); | ||
| } | ||
|
|
||
| </script> | ||
|
|
||
| <style setup lang="postcss" scoped> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grammar: the confirmation text is missing an article and reads a bit awkwardly.