- Refactor WorkspacePolicy to use pivot role instead of workspace.user_id - Add manageBilling policy (owner only) to BillingController - Fix ApiKeyController authorization (view → manageTeam for store/destroy) - Fix WorkspaceInviteController using workspace.user_id for owner checks - Fix WorkspaceController settings is_owner using workspace.user_id - Create PostAction enum for UpdatePost/PostController action strings - Create ApiToken\Status enum - Add User::SUBSCRIPTION_NAME constant, replace all hardcoded 'default' - Convert wantsEmailFor to accept NotificationType enum - Convert all $data[] to data_get() across publishers, controllers, jobs - Fix SocialLoginController callback missing try/catch - Fix SocialController::toggleActive missing workspace null check - Fix UpdatePost NPE on meta merge when postPlatform not found - Remove HTML5 required attributes from form inputs - Convert function declarations to arrow functions in Vue components - Replace hardcoded URLs with Wayfinder route helpers - Replace new Date() with dayjs - Add 16 new test files covering policies, authorization, publishing
66 lines
2.4 KiB
Vue
66 lines
2.4 KiB
Vue
<script setup lang="ts">
|
|
import { router, usePage } from '@inertiajs/vue3';
|
|
import { IconCheck, IconPlus, IconSelector } from '@tabler/icons-vue';
|
|
import { computed } from 'vue';
|
|
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from '@/components/ui/dropdown-menu';
|
|
import { create as createWorkspaceRoute, switchMethod } from '@/routes/app/workspaces';
|
|
|
|
interface Workspace {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
|
|
const page = usePage();
|
|
const currentWorkspace = computed<Workspace | null>(() => page.props.auth.currentWorkspace as Workspace | null);
|
|
const workspaces = computed<Workspace[]>(() => page.props.auth.workspaces as Workspace[]);
|
|
|
|
const switchWorkspace = (workspace: Workspace) => {
|
|
router.post(switchMethod.url(workspace.id), {}, {
|
|
preserveScroll: true,
|
|
});
|
|
};
|
|
|
|
const createWorkspace = () => {
|
|
router.visit(createWorkspaceRoute.url());
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger :as-child="true">
|
|
<Button variant="outline" class="w-full justify-between gap-2 px-3" :class="{ 'text-muted-foreground': !currentWorkspace }">
|
|
<span class="truncate">{{ currentWorkspace?.name || 'Select workspace' }}</span>
|
|
<IconSelector class="h-4 w-4 shrink-0 opacity-50" />
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="start" class="w-56">
|
|
<DropdownMenuLabel>Workspaces</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem
|
|
v-for="workspace in workspaces"
|
|
:key="workspace.id"
|
|
class="cursor-pointer"
|
|
@click="switchWorkspace(workspace)"
|
|
>
|
|
<div class="flex w-full items-center justify-between">
|
|
<span class="truncate">{{ workspace.name }}</span>
|
|
<IconCheck v-if="currentWorkspace?.id === workspace.id" class="h-4 w-4 shrink-0" />
|
|
</div>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem class="cursor-pointer" @click="createWorkspace">
|
|
<IconPlus class="mr-2 h-4 w-4" />
|
|
Create workspace
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</template>
|