Restructure UX and seed a fully simulated organisation
Rework the dashboard, environment topology view, header navigation, and status rendering, and standardise selects on a shadcn-vue component. Replace the thin database seeder with a SimulatedEnvironmentSeeder that builds a fully wired, mostly-running organisation (ACTIVE server fleet, managed + GHCR registries, Gitea source provider, ClipBin app with production/staging environments, services, slices, endpoints, managed variables, build artifacts, and a completed/in-progress/failed operations history) so the new UI renders against realistic data.
This commit is contained in:
@@ -7,6 +7,9 @@ import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import {
|
||||
@@ -24,9 +27,9 @@ import type { BreadcrumbItem, NavItem } from "@/types";
|
||||
import { Link, usePage } from "@inertiajs/vue3";
|
||||
import {
|
||||
AppWindowIcon,
|
||||
BoltIcon,
|
||||
BoxesIcon,
|
||||
ClipboardListIcon,
|
||||
Check,
|
||||
ChevronsUpDown,
|
||||
Menu,
|
||||
Search,
|
||||
ServerIcon,
|
||||
@@ -45,7 +48,9 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
const page = usePage();
|
||||
const auth = computed(() => page.props.auth);
|
||||
|
||||
const isCurrentRoute = computed(() => (url: string) => page.url === url || page.url.startsWith(`${url}/`));
|
||||
const isCurrentRoute = computed(
|
||||
() => (url: string) => page.url === url || page.url.startsWith(`${url}/`),
|
||||
);
|
||||
|
||||
const activeItemStyles = computed(
|
||||
() => (url: string) =>
|
||||
@@ -62,17 +67,21 @@ const mainNavItems: NavItem[] = [
|
||||
// },
|
||||
];
|
||||
|
||||
const activeOrganisation = computed(() => page.props.organisation);
|
||||
|
||||
const organisations = computed(() => auth.value.user?.organisations ?? []);
|
||||
|
||||
if (page.props.organisation) {
|
||||
const organisationId = page.props?.organisation?.id;
|
||||
|
||||
mainNavItems.push({
|
||||
title: page.props.organisation.name,
|
||||
title: "Applications",
|
||||
href: new URL(
|
||||
route("organisations.show", {
|
||||
route("applications.index", {
|
||||
organisation: organisationId,
|
||||
}),
|
||||
).pathname,
|
||||
icon: BoltIcon,
|
||||
icon: AppWindowIcon,
|
||||
});
|
||||
mainNavItems.push({
|
||||
title: "Environments",
|
||||
@@ -83,15 +92,6 @@ if (page.props.organisation) {
|
||||
).pathname,
|
||||
icon: BoxesIcon,
|
||||
});
|
||||
mainNavItems.push({
|
||||
title: "Applications",
|
||||
href: new URL(
|
||||
route("applications.index", {
|
||||
organisation: organisationId,
|
||||
}),
|
||||
).pathname,
|
||||
icon: AppWindowIcon,
|
||||
});
|
||||
mainNavItems.push({
|
||||
title: "Servers",
|
||||
href: new URL(
|
||||
@@ -110,24 +110,6 @@ if (page.props.organisation) {
|
||||
).pathname,
|
||||
icon: WorkflowIcon,
|
||||
});
|
||||
|
||||
if (
|
||||
page.props.organisation.providers_count === 0 ||
|
||||
page.props.organisation.source_providers_count === 0 ||
|
||||
page.props.organisation.registries_count === 0 ||
|
||||
page.props.organisation.servers_count === 0 ||
|
||||
page.props.organisation.applications_count === 0
|
||||
) {
|
||||
mainNavItems.push({
|
||||
title: "Onboarding",
|
||||
href: new URL(
|
||||
route("onboarding.show", {
|
||||
organisation: organisationId,
|
||||
}),
|
||||
).pathname,
|
||||
icon: ClipboardListIcon,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const rightNavItems: NavItem[] = [
|
||||
@@ -206,6 +188,36 @@ const rightNavItems: NavItem[] = [
|
||||
<AppLogo />
|
||||
</Link>
|
||||
|
||||
<!-- Organisation switcher -->
|
||||
<DropdownMenu v-if="activeOrganisation">
|
||||
<DropdownMenuTrigger :as-child="true">
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="ml-2 h-9 max-w-[12rem] gap-1.5 px-2 text-sm font-medium"
|
||||
>
|
||||
<span class="truncate">{{ activeOrganisation.name }}</span>
|
||||
<ChevronsUpDown class="size-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" class="w-60">
|
||||
<DropdownMenuLabel>Organisations</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
v-for="organisation in organisations"
|
||||
:key="organisation.id"
|
||||
:as="Link"
|
||||
:href="route('organisations.show', { organisation: organisation.id })"
|
||||
class="cursor-pointer justify-between"
|
||||
>
|
||||
<span class="truncate">{{ organisation.name }}</span>
|
||||
<Check
|
||||
v-if="organisation.id === activeOrganisation.id"
|
||||
class="size-4 shrink-0"
|
||||
/>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<!-- Desktop Menu -->
|
||||
<div class="hidden h-full lg:flex lg:flex-1">
|
||||
<NavigationMenu class="ml-10 flex h-full items-stretch">
|
||||
|
||||
Reference in New Issue
Block a user