redirect to server show page if a gateway is not installed on a given server
This commit is contained in:
@@ -15,4 +15,8 @@ abstract class DatabaseDriver extends Driver
|
|||||||
?string $containerId = null,
|
?string $containerId = null,
|
||||||
?array $credentials = null,
|
?array $credentials = null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
abstract public function createUser(string $user, string $password): string;
|
||||||
|
|
||||||
|
// abstract public function createDatabase(string $db, string $user): string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class Postgres17Driver extends DatabaseDriver
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
new Step(
|
new Step(
|
||||||
name: 'Configure firewall',
|
name: 'Configure firewall', // @todo this should create a Firewallrule
|
||||||
script: 'ufw allow 5432/tcp || true',
|
script: 'ufw allow 5432/tcp || true',
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
@@ -69,4 +69,9 @@ class Postgres17Driver extends DatabaseDriver
|
|||||||
'db' => 'keystone',
|
'db' => 'keystone',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function createUser(string $user, string $password): string
|
||||||
|
{
|
||||||
|
return "psql -U {$this->credentials['user']} -d {$this->credentials['db']} -c \"CREATE USER {$user} WITH PASSWORD '{$password}';\"";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ class EnvironmentController extends Controller
|
|||||||
return inertia('environments/Show', [
|
return inertia('environments/Show', [
|
||||||
'environment' => $environment,
|
'environment' => $environment,
|
||||||
'servers' => inertia()->optional(function () use ($environment) {
|
'servers' => inertia()->optional(function () use ($environment) {
|
||||||
return $environment->application?->organisation?->servers->where('status', ServerStatus::ACTIVE)?->values() ?? [];
|
return $environment
|
||||||
|
->application
|
||||||
|
?->organisation
|
||||||
|
?->servers()
|
||||||
|
->where('status', ServerStatus::ACTIVE)
|
||||||
|
->with('services')
|
||||||
|
->get() ?? [];
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ function onChange(event) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<label
|
<label
|
||||||
class="relative rounded-lg border-2 border-white/20 px-3 py-1 has-[:checked]:border-white has-[:disabled]:opacity-40"
|
class="relative rounded-lg border-2 dark:border-white/20 px-3 py-1 dark:has-[:checked]:border-white border-black/20 has-[:checked]:border-black has-[:disabled]:opacity-40"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
|
|||||||
@@ -1,19 +1,29 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
|
||||||
import { Deferred, router } from '@inertiajs/vue3';
|
import { Deferred, router } from '@inertiajs/vue3';
|
||||||
|
import { LoaderCircleIcon } from 'lucide-vue-next';
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import { Card } from './ui/card';
|
import { Card } from './ui/card';
|
||||||
import { LoaderCircleIcon } from 'lucide-vue-next';
|
import ServiceCategory from '@/enums/ServiceCategory';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
servers: {
|
servers: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
serviceCategory: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
validate: (value) => {
|
||||||
|
return Object.keys(ServiceCategory).includes(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const isOpen = ref(false);
|
const isOpen = ref(false);
|
||||||
|
|
||||||
|
defineEmits(['select']);
|
||||||
|
|
||||||
watch(isOpen, () => {
|
watch(isOpen, () => {
|
||||||
if (isOpen.value && props.servers === undefined) {
|
if (isOpen.value && props.servers === undefined) {
|
||||||
router.reload({
|
router.reload({
|
||||||
@@ -36,28 +46,32 @@ watch(isOpen, () => {
|
|||||||
<Deferred data="servers">
|
<Deferred data="servers">
|
||||||
<template #fallback>
|
<template #fallback>
|
||||||
<div class="flex justify-center py-4">
|
<div class="flex justify-center py-4">
|
||||||
<LoaderCircleIcon class="text-muted-foreground size-6 animate-spin" />
|
<LoaderCircleIcon class="size-6 animate-spin text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<Card
|
<Card
|
||||||
v-for="(server, serverIndex) in servers"
|
v-for="(server, serverIndex) in servers"
|
||||||
:key="`serverPicker-${server.id}`"
|
:key="`serverPicker-${server.id}`"
|
||||||
:data-index="serverIndex"
|
:data-index="serverIndex"
|
||||||
class="flex gap-4 p-2"
|
class="group flex gap-4 p-2 justify-between text-muted-foreground hover:text-foreground transition"
|
||||||
:class="{
|
:class="{
|
||||||
'rounded-b-none': serverIndex !== servers.length - 1,
|
'rounded-b-none': serverIndex !== servers.length - 1,
|
||||||
'rounded-t-none': serverIndex !== 0,
|
'rounded-t-none': serverIndex !== 0,
|
||||||
'border-b-0': serverIndex !== servers.length - 1,
|
'border-b-0': serverIndex !== servers.length - 1,
|
||||||
}"
|
}"
|
||||||
|
@click="
|
||||||
|
$emit('select', server);
|
||||||
|
isOpen = false;
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<div>{{ server.name }}</div>
|
<div class="cursor-default text-sm">{{ server.name }}</div>
|
||||||
<div></div>
|
<div v-if="serviceCategory" class="text-xs">{{ !!server.services.filter((s) => s.category === serviceCategory).length ? 'Has Gateway' : 'No Gateway Installed' }}</div>
|
||||||
</Card>
|
</Card>
|
||||||
<Card v-if="servers.length === 0" class="p-2 text-sm text-muted-foreground"> No servers available </Card>
|
<Card v-if="servers.length === 0" class="p-2 text-sm text-muted-foreground"> No servers available </Card>
|
||||||
</Deferred>
|
</Deferred>
|
||||||
</div>
|
</div>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogFooter> Dismiss </DialogFooter>
|
<!-- <DialogFooter> Dismiss </DialogFooter> -->
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup>
|
||||||
import ServerSelector from '@/components/ServerSelector.vue';
|
import ServerSelector from '@/components/ServerSelector.vue';
|
||||||
import { Card } from '@/components/ui/card';
|
import { Card } from '@/components/ui/card';
|
||||||
|
import ServiceCategory from '@/enums/ServiceCategory';
|
||||||
import AppLayout from '@/layouts/AppLayout.vue';
|
import AppLayout from '@/layouts/AppLayout.vue';
|
||||||
import { Head } from '@inertiajs/vue3';
|
import { Head, router, usePage } from '@inertiajs/vue3';
|
||||||
import { PlusIcon } from 'lucide-vue-next';
|
import { PlusIcon } from 'lucide-vue-next';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
@@ -15,6 +16,20 @@ defineProps({
|
|||||||
required: false,
|
required: false,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function selectServer(server, serviceCategory = null) {
|
||||||
|
if (serviceCategory) {
|
||||||
|
if (server.services?.find((s) => s.category === serviceCategory)) {
|
||||||
|
// service is installed
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
router.visit(route('servers.show', {
|
||||||
|
organisation: usePage().props.organisation.id,
|
||||||
|
server: server.id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -35,6 +50,10 @@ defineProps({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Environments',
|
title: 'Environments',
|
||||||
|
href: route('applications.show', {
|
||||||
|
organisation: $page.props.organisation.id,
|
||||||
|
application: environment.application.id,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: environment.name,
|
title: environment.name,
|
||||||
@@ -49,7 +68,7 @@ defineProps({
|
|||||||
<div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
|
<div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
|
||||||
<Card class="pattern-graph-paper grid grid-cols-3 gap-6 p-6">
|
<Card class="pattern-graph-paper grid grid-cols-3 gap-6 p-6">
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<ServerSelector :servers="servers">
|
<ServerSelector :servers="servers" :service-category="ServiceCategory.GATEWAY" @select="selectServer($event, ServiceCategory.GATEWAY)">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<Card class="group flex select-none items-center gap-2 bg-card/30 p-4 text-sm backdrop-blur-sm">
|
<Card class="group flex select-none items-center gap-2 bg-card/30 p-4 text-sm backdrop-blur-sm">
|
||||||
<PlusIcon class="size-4 opacity-50" />
|
<PlusIcon class="size-4 opacity-50" />
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { useCycleList, useInterval } from '@vueuse/core';
|
|||||||
import { DatabaseIcon, Layers2Icon, LoaderCircleIcon, PlusIcon } from 'lucide-vue-next';
|
import { DatabaseIcon, Layers2Icon, LoaderCircleIcon, PlusIcon } from 'lucide-vue-next';
|
||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
server: {
|
server: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user