AcceptInviteController attached invited users with a hardcoded member role, ignoring the invite's role entirely (a viewer invite joined as member). Use the invite's role on accept, require role on invite creation (no silent default), and drop the role from the request/CreateInvite defaults. Add the Viewer option to the member role dropdown (now iterates all roles), hide the dropdown on the current user's own row, and require the member's email to confirm removal. Covered by tests asserting the accepted role matches the invited role for viewer/admin/member, plus invite role validation.
68 lines
1.9 KiB
Vue
68 lines
1.9 KiB
Vue
<script setup lang="ts">
|
|
import { Head } from '@inertiajs/vue3';
|
|
import { trans } from 'laravel-vue-i18n';
|
|
import { computed } from 'vue';
|
|
|
|
import PageHeader from '@/components/PageHeader.vue';
|
|
import SettingsTabsNav from '@/components/settings/SettingsTabsNav.vue';
|
|
import UsersTab from '@/components/settings/UsersTab.vue';
|
|
import AppLayout from '@/layouts/AppLayout.vue';
|
|
import { members as membersRoute } from '@/routes/app';
|
|
import { index as apiKeysRoute } from '@/routes/app/api-keys';
|
|
import { brand as brandRoute, settings as workspaceSettings } from '@/routes/app/workspace';
|
|
|
|
interface Workspace {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
|
|
interface Member {
|
|
id: string;
|
|
name: string;
|
|
email: string;
|
|
role: string;
|
|
}
|
|
|
|
interface Invite {
|
|
id: string;
|
|
email: string;
|
|
role: string;
|
|
}
|
|
|
|
interface Role {
|
|
value: string;
|
|
label: string;
|
|
}
|
|
|
|
defineProps<{
|
|
workspace: Workspace;
|
|
owner: Member;
|
|
members: Member[];
|
|
invites: Invite[];
|
|
roles: Role[];
|
|
}>();
|
|
|
|
const tabs = computed(() => [
|
|
{ name: 'workspace', label: trans('settings.workspace.tabs.workspace'), href: workspaceSettings.url() },
|
|
{ name: 'brand', label: trans('settings.workspace.tabs.brand'), href: brandRoute.url() },
|
|
{ name: 'members', label: trans('settings.workspace.tabs.users'), href: membersRoute.url() },
|
|
{ name: 'api-keys', label: trans('settings.workspace.tabs.api_keys'), href: apiKeysRoute.url() },
|
|
]);
|
|
</script>
|
|
|
|
<template>
|
|
<Head :title="$t('settings.members.title')" />
|
|
|
|
<AppLayout>
|
|
<div class="mx-auto max-w-4xl space-y-8 px-6 py-8">
|
|
<PageHeader
|
|
:title="$t('settings.hub.title')"
|
|
:description="$t('settings.hub.description')"
|
|
/>
|
|
|
|
<SettingsTabsNav :tabs="tabs" active="members" />
|
|
|
|
<UsersTab :members="members" :invitations="invites" :roles="roles" />
|
|
</div>
|
|
</AppLayout>
|
|
</template>
|