Skip to content

Add members invite, role change, and remove CRUD - #2

Merged
suporterfid merged 1 commit into
mainfrom
feat/members-crud
Jul 19, 2026
Merged

suporterfid merged 1 commit into
mainfrom
feat/members-crud

Conversation

@suporterfid

Copy link
Copy Markdown
Owner

Summary

  • Tenant-admin invite/create membership (existing or new user + password reset)
  • Role change and remove with last-admin and self-remove guards + audit events
  • Inline /members UI matching Environments/API Keys

Test plan

  • Invite existing user and new email on https://hub.taskconnect.com.br/members
  • Change role; demoting last admin fails
  • Remove member; self-remove and last-admin remove fail
  • Non-admin can list but gets 403 on write

Made with Cursor

Tenant admins can manage memberships on /members with last-admin
and self-remove guards, audit events, and inline UI matching Environments.

Co-authored-by: Cursor <cursoragent@cursor.com>
@suporterfid
suporterfid merged commit 4f7ce1a into main Jul 19, 2026
1 check failed
@suporterfid
suporterfid deleted the feat/members-crud branch July 19, 2026 01:36

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the Members CRUD functionality, allowing tenant administrators to invite members, update their roles, and remove them. The backend changes introduce a new MemberService, MemberPolicy, and corresponding controller endpoints with audit logging and feature tests. On the frontend, MembersPage.vue is updated with inline forms for inviting and editing members, alongside localization support and updated TypeScript types. The review feedback highlights several dark mode styling omissions in the new frontend form and table components, which can cause readability and contrast issues on dark backgrounds.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +186 to +208
<label v-if="!editingId" class="block">
<span class="mb-1 block text-sm font-medium text-gray-700">{{
$t('settings.members.fields.email')
}}</span>
<input
v-model="form.email"
type="email"
required
class="w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
/>
</label>
<label v-if="!editingId" class="block">
<span class="mb-1 block text-sm font-medium text-gray-700">{{
$t('settings.members.fields.name')
}}</span>
<input
v-model="form.name"
class="w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
/>
<span class="mt-1 block text-xs text-gray-500">{{
$t('settings.members.fields.nameHint')
}}</span>
</label>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The form labels and input fields lack dark mode classes. In dark mode, the form container has a dark background (dark:bg-gray-900), but these inputs will remain white with low-contrast labels, making them hard to read and visually inconsistent. Let's add appropriate Tailwind dark mode classes (dark:text-gray-300, dark:border-gray-700, dark:bg-gray-800, dark:text-gray-100) to ensure a seamless dark mode experience.

        <label v-if="!editingId" class="block">
          <span class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300">{{
            $t('settings.members.fields.email')
          }}</span>
          <input
            v-model="form.email"
            type="email"
            required
            class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100"
          />
        </label>
        <label v-if="!editingId" class="block">
          <span class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300">{{
            $t('settings.members.fields.name')
          }}</span>
          <input
            v-model="form.name"
            class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100"
          />
          <span class="mt-1 block text-xs text-gray-500 dark:text-gray-400">{{
            $t('settings.members.fields.nameHint')
          }}</span>
        </label>

Comment on lines +215 to +228
<label class="block">
<span class="mb-1 block text-sm font-medium text-gray-700">{{
$t('settings.members.fields.role')
}}</span>
<select
v-model="form.role"
required
class="w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
>
<option v-for="role in ROLE_OPTIONS" :key="role" :value="role">
{{ roleLabel(role) }}
</option>
</select>
</label>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similarly, the role select element and its label should also support dark mode to match the rest of the form.

        <label class="block">
          <span class="mb-1 block text-sm font-medium text-gray-700 dark:text-gray-300">{{
            $t('settings.members.fields.role')
          }}</span>
          <select
            v-model="form.role"
            required
            class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100"
          >
            <option v-for="role in ROLE_OPTIONS" :key="role" :value="role">
              {{ roleLabel(role) }}
            </option>
          </select>
        </label>

<tbody class="divide-y divide-gray-200 bg-white dark:divide-gray-800 dark:bg-gray-950">
<tr v-for="member in data" :key="member.id">
<td class="px-4 py-3 font-medium">{{ member.name }}</td>
<td class="px-4 py-3 text-sm text-gray-600">{{ member.email }}</td>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The text-gray-600 class has very low contrast on dark backgrounds (like dark:bg-gray-950). Let's add dark:text-gray-400 to ensure the email address is readable in dark mode.

            <td class="px-4 py-3 text-sm text-gray-600 dark:text-gray-400">{{ member.email }}</td>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant