Header layout rather than sidebar layout
This commit is contained in:
@@ -2,10 +2,20 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Organisation;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ApplicationController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$organisation = Organisation::with('applications')->findOrFail($request->route('organisation'));
|
||||
|
||||
return inertia('applications/Index', [
|
||||
'applications' => $organisation->applications,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Request $request)
|
||||
{
|
||||
$id = $request->route('application');
|
||||
|
||||
@@ -18,7 +18,7 @@ import UserMenuContent from '@/components/UserMenuContent.vue';
|
||||
import { getInitials } from '@/composables/useInitials';
|
||||
import type { BreadcrumbItem, NavItem } from '@/types';
|
||||
import { Link, usePage } from '@inertiajs/vue3';
|
||||
import { BookOpen, Folder, LayoutGrid, Menu, Search } from 'lucide-vue-next';
|
||||
import { AppWindowIcon, BookOpen, Folder, LayoutGrid, Menu, Search, ServerIcon } from 'lucide-vue-next';
|
||||
import { computed } from 'vue';
|
||||
|
||||
interface Props {
|
||||
@@ -39,24 +39,41 @@ const activeItemStyles = computed(
|
||||
);
|
||||
|
||||
const mainNavItems: NavItem[] = [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
href: '/dashboard',
|
||||
icon: LayoutGrid,
|
||||
},
|
||||
// {
|
||||
// title: 'Dashboard',
|
||||
// href: new URL(route('dashboard')).pathname,
|
||||
// icon: LayoutGrid,
|
||||
// },
|
||||
];
|
||||
|
||||
if (page.props.organisation) {
|
||||
mainNavItems.push({
|
||||
title: 'Applications',
|
||||
href: new URL(route('applications.index', {
|
||||
organisation: page.props?.organisation?.id
|
||||
})).pathname,
|
||||
icon: AppWindowIcon,
|
||||
});
|
||||
mainNavItems.push({
|
||||
title: 'Servers',
|
||||
href: new URL(route('servers.index', {
|
||||
organisation: page.props?.organisation?.id
|
||||
})).pathname,
|
||||
icon: ServerIcon,
|
||||
})
|
||||
}
|
||||
|
||||
const rightNavItems: NavItem[] = [
|
||||
{
|
||||
title: 'Repository',
|
||||
href: 'https://github.com/laravel/vue-starter-kit',
|
||||
icon: Folder,
|
||||
},
|
||||
{
|
||||
title: 'Documentation',
|
||||
href: 'https://laravel.com/docs/starter-kits',
|
||||
icon: BookOpen,
|
||||
},
|
||||
// {
|
||||
// title: 'Repository',
|
||||
// href: 'https://github.com/laravel/vue-starter-kit',
|
||||
// icon: Folder,
|
||||
// },
|
||||
// {
|
||||
// title: 'Documentation',
|
||||
// href: 'https://laravel.com/docs/starter-kits',
|
||||
// icon: BookOpen,
|
||||
// },
|
||||
];
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { WavesIcon } from 'lucide-vue-next';
|
||||
import type { HTMLAttributes } from 'vue';
|
||||
|
||||
defineOptions({
|
||||
@@ -13,12 +14,5 @@ defineProps<Props>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 42" :class="className" v-bind="$attrs">
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M17.2 5.633 8.6.855 0 5.633v26.51l16.2 9 16.2-9v-8.442l7.6-4.223V9.856l-8.6-4.777-8.6 4.777V18.3l-5.6 3.111V5.633ZM38 18.301l-5.6 3.11v-6.157l5.6-3.11V18.3Zm-1.06-7.856-5.54 3.078-5.54-3.079 5.54-3.078 5.54 3.079ZM24.8 18.3v-6.157l5.6 3.111v6.158L24.8 18.3Zm-1 1.732 5.54 3.078-13.14 7.302-5.54-3.078 13.14-7.3v-.002Zm-16.2 7.89 7.6 4.222V38.3L2 30.966V7.92l5.6 3.111v16.892ZM8.6 9.3 3.06 6.222 8.6 3.143l5.54 3.08L8.6 9.3Zm21.8 15.51-13.2 7.334V38.3l13.2-7.334v-6.156ZM9.6 11.034l5.6-3.11v14.6l-5.6 3.11v-14.6Z"
|
||||
/>
|
||||
</svg>
|
||||
<WavesIcon v-bind="$attrs" :class="className" />
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import AppLayout from '@/layouts/app/AppSidebarLayout.vue';
|
||||
import AppLayout from '@/layouts/app/AppHeaderLayout.vue';
|
||||
import type { BreadcrumbItemType } from '@/types';
|
||||
|
||||
interface Props {
|
||||
|
||||
54
resources/js/pages/Applications/Index.vue
Normal file
54
resources/js/pages/Applications/Index.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<script setup>
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { Head, Link } from '@inertiajs/vue3';
|
||||
|
||||
const props = defineProps({
|
||||
applications: {
|
||||
type: [Object, null],
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head title="Dashboard" />
|
||||
|
||||
<AppLayout
|
||||
:breadcrumbs="[
|
||||
{
|
||||
title: 'Applications',
|
||||
href: route('applications.index', {
|
||||
organisation: $page.props.organisation.id,
|
||||
}),
|
||||
},
|
||||
]"
|
||||
>
|
||||
<div class="flex justify-between items-center gap-3 p-4">
|
||||
<h2 class="text-3xl font-bold tracking-tight">Applications</h2>
|
||||
<div>
|
||||
<!-- <Button :as="Link" :href="route('applications.create', {
|
||||
organisation: $page.props.organisation.id,
|
||||
})">Create</Button> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-4 rounded-xl p-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
<Card v-for="application in applications.data" :key="`application{$applications.id}`" class="relative w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>{{ application.name }}</CardTitle>
|
||||
</CardHeader>
|
||||
<Link
|
||||
:href="
|
||||
route('applications.show', {
|
||||
organisation: $page.props.organisation.id,
|
||||
application: application.id,
|
||||
})
|
||||
"
|
||||
class="absolute inset-0"
|
||||
></Link>
|
||||
</Card>
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
@@ -1,8 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { type BreadcrumbItem } from '@/types';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import PlaceholderPattern from '../components/PlaceholderPattern.vue';
|
||||
import { Head, Link } from '@inertiajs/vue3';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { ChevronRightIcon } from 'lucide-vue-next';
|
||||
|
||||
defineProps({
|
||||
organisations: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const breadcrumbs: BreadcrumbItem[] = [
|
||||
{
|
||||
@@ -16,16 +24,21 @@ const breadcrumbs: BreadcrumbItem[] = [
|
||||
<Head title="Dashboard" />
|
||||
|
||||
<AppLayout :breadcrumbs="breadcrumbs">
|
||||
<div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
|
||||
<div>The plan:</div>
|
||||
<div>Organisations have applications</div>
|
||||
<div>Applications have environments</div>
|
||||
<div>Servers have services</div>
|
||||
<div>Services have slices, this could be a database table or a client in a websocket server</div>
|
||||
<div>Environments have SLICES</div>
|
||||
<div>Also servers need to be provisioned</div>
|
||||
<div>Users have SSH keys</div>
|
||||
<div>Keystone has its own SSH keys</div>
|
||||
<div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4 items-center">
|
||||
<Card class="w-80">
|
||||
<CardHeader class="border-b border-b-muted-background">
|
||||
<CardTitle>Your Organisation</CardTitle>
|
||||
<CardDescription>
|
||||
Select an organisation to view its details.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent class="divide-y divide-y-muted-foreground p-0">
|
||||
<Link v-for="organisation in organisations" :href="route('organisations.show', { organisation: organisation.id })" class="py-3 px-6 hover:bg-muted flex justify-between items-center">
|
||||
<div>{{ organisation.name }}</div>
|
||||
<ChevronRightIcon class="size-4 text-muted-foreground" />
|
||||
</Link>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
@@ -82,7 +82,7 @@ defineProps({
|
||||
<template #fallback> Loading... </template>
|
||||
<h3 class="mt-4 text-2xl font-bold tracking-tight">Server Providers</h3>
|
||||
<p class="mb-4 text-sm text-muted-foreground">Manage your server providers.</p>
|
||||
<div class="border-muted-background divide-y-muted-background divide-y rounded-md border">
|
||||
<div class="border-muted-background divide-y-muted-background divide-y rounded-md border max-w-80">
|
||||
<div v-for="provider in providers" class="flex items-center gap-2 px-2 py-1">
|
||||
{{ provider.name }}
|
||||
<span class="ml-auto text-xs uppercase text-muted-foreground">{{ provider.type }}</span>
|
||||
|
||||
@@ -12,7 +12,11 @@ use Illuminate\Support\Facades\Route;
|
||||
Route::inertia('/', 'Welcome')->name('home');
|
||||
|
||||
Route::middleware(['auth', 'verified'])->group(function () {
|
||||
Route::inertia('dashboard', 'Dashboard')->name('dashboard');
|
||||
Route::get('/dashboard', function () {
|
||||
return inertia('Dashboard', [
|
||||
'organisations' => auth()->user()->organisations,
|
||||
]);
|
||||
})->name('dashboard');
|
||||
|
||||
Route::prefix('organisations/{organisation}')->group(function () {
|
||||
Route::get('/', [OrganisationController::class, 'show'])->name('organisations.show');
|
||||
|
||||
Reference in New Issue
Block a user