icons on service create, firewall rule remove/install
This commit is contained in:
@@ -11,4 +11,5 @@ enum FirewallRuleStatus: string
|
|||||||
case NOT_APPLIED = 'not-applied';
|
case NOT_APPLIED = 'not-applied';
|
||||||
case APPLIED = 'applied';
|
case APPLIED = 'applied';
|
||||||
case FAILED = 'failed';
|
case FAILED = 'failed';
|
||||||
|
case REMOVED = 'removed';
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ enum ServiceCategory: string
|
|||||||
return match ($category) {
|
return match ($category) {
|
||||||
self::APPLICATION => 'The base container image for your application',
|
self::APPLICATION => 'The base container image for your application',
|
||||||
self::DATABASE => 'Postgres or MySQL',
|
self::DATABASE => 'Postgres or MySQL',
|
||||||
self::GATEWAY => 'The gateway is the first point of contact for your application',
|
self::GATEWAY => 'The first point of contact for your application',
|
||||||
self::STORAGE => 'S3 or S3-compatible service',
|
self::STORAGE => 'S3 or S3-compatible service',
|
||||||
self::CACHE => 'Redis, Memcached or similar',
|
self::CACHE => 'Redis, Memcached or similar',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class FirewallRule extends Model
|
|||||||
parent::boot();
|
parent::boot();
|
||||||
|
|
||||||
static::created(function (self $firewallRule) {
|
static::created(function (self $firewallRule) {
|
||||||
$firewallRule->execute();
|
$firewallRule->install();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ class FirewallRule extends Model
|
|||||||
return $this->belongsTo(Server::class);
|
return $this->belongsTo(Server::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(): void
|
public function install(): void
|
||||||
{
|
{
|
||||||
$ssh = $this->server->sshClient();
|
$ssh = $this->server->sshClient();
|
||||||
|
|
||||||
@@ -62,4 +62,36 @@ class FirewallRule extends Model
|
|||||||
'status' => FirewallRuleStatus::APPLIED,
|
'status' => FirewallRuleStatus::APPLIED,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function remove(): void
|
||||||
|
{
|
||||||
|
$ssh = $this->server->sshClient();
|
||||||
|
|
||||||
|
$command = "ufw";
|
||||||
|
|
||||||
|
if ($this->type === 'allow') {
|
||||||
|
$command .= " delete allow";
|
||||||
|
} elseif ($this->type === 'deny') {
|
||||||
|
$command .= " delete deny";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->from) {
|
||||||
|
$command .= " from {$this->from}";
|
||||||
|
$command .= " to any port";
|
||||||
|
}
|
||||||
|
|
||||||
|
$command .= " {$this->ports}";
|
||||||
|
|
||||||
|
$result = $ssh->execute($command);
|
||||||
|
|
||||||
|
if (! $result->isSuccessful()) {
|
||||||
|
$this->update([
|
||||||
|
'status' => FirewallRuleStatus::FAILED,
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->update([
|
||||||
|
'status' => FirewallRuleStatus::REMOVED,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
// Published at 2025-04-01 16:27:12
|
// Published at 2025-04-06 16:01:50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"PENDING": "pending",
|
"PENDING": "pending",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
// Published at 2025-04-01 16:27:12
|
// Published at 2025-04-06 16:01:50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"NOT_APPLIED": "not-applied",
|
"NOT_APPLIED": "not-applied",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
// Published at 2025-04-01 16:27:12
|
// Published at 2025-04-06 16:01:50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"ADMIN": "admin",
|
"ADMIN": "admin",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
// Published at 2025-04-01 16:27:12
|
// Published at 2025-04-06 16:01:50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"GIT": "git"
|
"GIT": "git"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
// Published at 2025-04-01 16:27:12
|
// Published at 2025-04-06 16:01:50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"HETZNER": "hetzner",
|
"HETZNER": "hetzner",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
// Published at 2025-04-01 16:27:12
|
// Published at 2025-04-06 16:01:50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"WAITING_FOR_PROVIDER": "waiting-for-provider",
|
"WAITING_FOR_PROVIDER": "waiting-for-provider",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
// Published at 2025-04-01 16:27:12
|
// Published at 2025-04-06 16:01:50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"DATABASE": "database",
|
"DATABASE": "database",
|
||||||
@@ -12,7 +12,7 @@ export default {
|
|||||||
export const DescriptionMap = {
|
export const DescriptionMap = {
|
||||||
"DATABASE": "Postgres or MySQL",
|
"DATABASE": "Postgres or MySQL",
|
||||||
"APPLICATION": "The base container image for your application",
|
"APPLICATION": "The base container image for your application",
|
||||||
"GATEWAY": "The gateway is the first point of contact for your application",
|
"GATEWAY": "The first point of contact for your application",
|
||||||
"STORAGE": "S3 or S3-compatible service",
|
"STORAGE": "S3 or S3-compatible service",
|
||||||
"CACHE": "Redis, Memcached or similar"
|
"CACHE": "Redis, Memcached or similar"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
// Published at 2025-04-01 16:27:12
|
// Published at 2025-04-06 16:01:50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"NOT_INSTALLED": "not-installed",
|
"NOT_INSTALLED": "not-installed",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
// Published at 2025-04-01 16:27:12
|
// Published at 2025-04-06 16:01:50
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
"FRANKENPHP": "frankenphp",
|
"FRANKENPHP": "frankenphp",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Input } from '@/components/ui/input';
|
|||||||
import InputError from '@/components/InputError.vue';
|
import InputError from '@/components/InputError.vue';
|
||||||
import ServiceCategory, { DescriptionMap as serviceCategoryDescriptions } from '@/enums/ServiceCategory';
|
import ServiceCategory, { DescriptionMap as serviceCategoryDescriptions } from '@/enums/ServiceCategory';
|
||||||
import RadioButton from '@/components/RadioButton.vue';
|
import RadioButton from '@/components/RadioButton.vue';
|
||||||
|
import { AppWindowIcon, ArchiveIcon, DatabaseIcon, DatabaseZapIcon, DoorOpenIcon } from 'lucide-vue-next';
|
||||||
|
|
||||||
const props = defineProps({});
|
const props = defineProps({});
|
||||||
|
|
||||||
@@ -15,6 +16,23 @@ const form = useForm({
|
|||||||
category: null,
|
category: null,
|
||||||
type: null,
|
type: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getIcon(category) {
|
||||||
|
switch (category) {
|
||||||
|
case ServiceCategory.DATABASE:
|
||||||
|
return DatabaseIcon;
|
||||||
|
case ServiceCategory.CACHE:
|
||||||
|
return DatabaseZapIcon;
|
||||||
|
case ServiceCategory.APPLICATION:
|
||||||
|
return AppWindowIcon;
|
||||||
|
case ServiceCategory.GATEWAY:
|
||||||
|
return DoorOpenIcon;
|
||||||
|
case ServiceCategory.STORAGE:
|
||||||
|
return ArchiveIcon;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -37,15 +55,19 @@ const form = useForm({
|
|||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<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">
|
||||||
<div class="flex gap-2">
|
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-2">
|
||||||
<RadioButton
|
<RadioButton
|
||||||
v-for="(category, categoryKey) in ServiceCategory"
|
v-for="(category, categoryKey) in ServiceCategory"
|
||||||
v-model="form.category"
|
v-model="form.category"
|
||||||
:value="category"
|
:value="category"
|
||||||
name="category"
|
name="category"
|
||||||
|
class="py-3 flex gap-3"
|
||||||
>
|
>
|
||||||
<h4 class="text-lg font-semibold tracking-tighter">{{ category }}</h4>
|
<component :is="getIcon(category)" class="size-5" />
|
||||||
<p class="text-sm">{{ serviceCategoryDescriptions[categoryKey] }}</p>
|
<div>
|
||||||
|
<h4 class="text-lg font-semibold tracking-tighter leading-none mb-1">{{ category }}</h4>
|
||||||
|
<p class="text-sm">{{ serviceCategoryDescriptions[categoryKey] }}</p>
|
||||||
|
</div>
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user