parent
08ba19f355
commit
563721e67c
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\airflow;
|
||||
use App\Models\User;
|
||||
|
||||
class AirFlowTargetTable extends BaseTableComponent
|
||||
{
|
||||
public function mount()
|
||||
{
|
||||
$this->headers = ['ID', 'Имя', 'URL', 'Username', 'Порт', 'Версия', 'Активный'];
|
||||
$this->data = Airflow::all(['id', 'name', 'url', 'username', 'port', 'version', 'is_active'])->toArray();
|
||||
$this->view_item_route = "airflow.view";
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\airflow;
|
||||
use Livewire\Component;
|
||||
|
||||
class AirflowDataView extends Component
|
||||
{
|
||||
public $airflowId;
|
||||
public $airflow;
|
||||
|
||||
public function mount($airflowId)
|
||||
{
|
||||
$this->airflowId = $airflowId;
|
||||
$this->loadAirflowData();
|
||||
}
|
||||
|
||||
public function loadAirflowData()
|
||||
{
|
||||
$this->airflow = Airflow::with('user')->find($this->airflowId);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.airflow-data-view');
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\airflow;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class AirflowForm extends Component
|
||||
{
|
||||
public $name;
|
||||
public $url;
|
||||
public $username;
|
||||
public $password;
|
||||
public $api_token;
|
||||
public $port;
|
||||
public $version;
|
||||
|
||||
public function submit()
|
||||
{
|
||||
$this->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'url' => 'required|url',
|
||||
'username' => 'required|string|max:255',
|
||||
'password' => 'required|string|max:255',
|
||||
'api_token' => 'nullable|string|max:255',
|
||||
'port' => 'required|integer',
|
||||
'version' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
Airflow::create([
|
||||
'name' => $this->name,
|
||||
'url' => $this->url,
|
||||
'username' => $this->username,
|
||||
'password' => $this->password,
|
||||
'api_token' => $this->api_token,
|
||||
'port' => $this->port,
|
||||
'version' => $this->version,
|
||||
'user_id' => Auth::user()->id,
|
||||
]);
|
||||
|
||||
session()->flash('message', 'Airflow cluster created successfully.');
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.airflow-form');
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class BaseTableComponent extends Component
|
||||
{
|
||||
public $data = [];
|
||||
public $headers = [];
|
||||
public $view_item_route = null;
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.base-table-component');
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class UsersTable extends Component
|
||||
{
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.users-table');
|
||||
}
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'models' => [
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your permissions. Of course, it
|
||||
* is often just the "Permission" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Permission model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Permission` contract.
|
||||
*/
|
||||
|
||||
'permission' => Spatie\Permission\Models\Permission::class,
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your roles. Of course, it
|
||||
* is often just the "Role" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Role model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Role` contract.
|
||||
*/
|
||||
|
||||
'role' => Spatie\Permission\Models\Role::class,
|
||||
|
||||
],
|
||||
|
||||
'table_names' => [
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'roles' => 'roles',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your permissions. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'permissions' => 'permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_permissions' => 'model_has_permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models roles. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_roles' => 'model_has_roles',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'role_has_permissions' => 'role_has_permissions',
|
||||
],
|
||||
|
||||
'column_names' => [
|
||||
/*
|
||||
* Change this if you want to name the related pivots other than defaults
|
||||
*/
|
||||
'role_pivot_key' => null, //default 'role_id',
|
||||
'permission_pivot_key' => null, //default 'permission_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to name the related model primary key other than
|
||||
* `model_id`.
|
||||
*
|
||||
* For example, this would be nice if your primary keys are all UUIDs. In
|
||||
* that case, name this `model_uuid`.
|
||||
*/
|
||||
|
||||
'model_morph_key' => 'model_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to use the teams feature and your related model's
|
||||
* foreign key is other than `team_id`.
|
||||
*/
|
||||
|
||||
'team_foreign_key' => 'team_id',
|
||||
],
|
||||
|
||||
/*
|
||||
* When set to true, the method for checking permissions will be registered on the gate.
|
||||
* Set this to false if you want to implement custom logic for checking permissions.
|
||||
*/
|
||||
|
||||
'register_permission_check_method' => true,
|
||||
|
||||
/*
|
||||
* When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered
|
||||
* this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated
|
||||
* NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it.
|
||||
*/
|
||||
'register_octane_reset_listener' => false,
|
||||
|
||||
/*
|
||||
* Teams Feature.
|
||||
* When set to true the package implements teams using the 'team_foreign_key'.
|
||||
* If you want the migrations to register the 'team_foreign_key', you must
|
||||
* set this to true before doing the migration.
|
||||
* If you already did the migration then you must make a new migration to also
|
||||
* add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions'
|
||||
* (view the latest version of this package's migration file)
|
||||
*/
|
||||
|
||||
'teams' => false,
|
||||
|
||||
/*
|
||||
* Passport Client Credentials Grant
|
||||
* When set to true the package will use Passports Client to check permissions
|
||||
*/
|
||||
|
||||
'use_passport_client_credentials' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required permission names are added to exception messages.
|
||||
* This could be considered an information leak in some contexts, so the default
|
||||
* setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_permission_in_exception' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required role names are added to exception messages.
|
||||
* This could be considered an information leak in some contexts, so the default
|
||||
* setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_role_in_exception' => false,
|
||||
|
||||
/*
|
||||
* By default wildcard permission lookups are disabled.
|
||||
* See documentation to understand supported syntax.
|
||||
*/
|
||||
|
||||
'enable_wildcard_permission' => false,
|
||||
|
||||
/*
|
||||
* The class to use for interpreting wildcard permissions.
|
||||
* If you need to modify delimiters, override the class and specify its name here.
|
||||
*/
|
||||
// 'permission.wildcard_permission' => Spatie\Permission\WildcardPermission::class,
|
||||
|
||||
/* Cache-specific settings */
|
||||
|
||||
'cache' => [
|
||||
|
||||
/*
|
||||
* By default all permissions are cached for 24 hours to speed up performance.
|
||||
* When permissions or roles are updated the cache is flushed automatically.
|
||||
*/
|
||||
|
||||
'expiration_time' => \DateInterval::createFromDateString('24 hours'),
|
||||
|
||||
/*
|
||||
* The cache key used to store all permissions.
|
||||
*/
|
||||
|
||||
'key' => 'spatie.permission.cache',
|
||||
|
||||
/*
|
||||
* You may optionally indicate a specific cache driver to use for permission and
|
||||
* role caching using any of the `store` drivers listed in the cache.php config
|
||||
* file. Using 'default' here means to use the `default` set in cache.php.
|
||||
*/
|
||||
|
||||
'store' => 'default',
|
||||
],
|
||||
];
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('airflows', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name'); // Имя кластера
|
||||
$table->string('url'); // URL или IP кластера Airflow
|
||||
$table->string('username')->nullable(); // Логин для доступа (если используется)
|
||||
$table->string('password')->nullable(); // Пароль для доступа (если используется)
|
||||
$table->string('api_token')->nullable(); // Токен для доступа (если используется)
|
||||
$table->string('port')->default('8080'); // Порт Airflow API
|
||||
$table->string('version')->nullable(); // Версия Airflow
|
||||
$table->boolean('is_active')->default(true); // Статус кластера (активен/неактивен)
|
||||
$table->foreignId('user_id')->constrained(); // Кто создал/управляет кластером
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('airflows');
|
||||
}
|
||||
};
|
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('dags', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('user_id');
|
||||
$table->foreignId('airflow_id')->constrained('airflows')->onDelete('cascade');
|
||||
$table->string('name');
|
||||
$table->string('description')->nullable();
|
||||
$table->string('file_path');
|
||||
$table->enum('status', ['pending', 'approved', 'rejected'])->default('pending');
|
||||
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('dags');
|
||||
}
|
||||
};
|
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$teams = config('permission.teams');
|
||||
$tableNames = config('permission.table_names');
|
||||
$columnNames = config('permission.column_names');
|
||||
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
|
||||
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
|
||||
|
||||
if (empty($tableNames)) {
|
||||
throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
}
|
||||
if ($teams && empty($columnNames['team_foreign_key'] ?? null)) {
|
||||
throw new \Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
}
|
||||
|
||||
Schema::create($tableNames['permissions'], function (Blueprint $table) {
|
||||
//$table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // permission id
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['name', 'guard_name']);
|
||||
});
|
||||
|
||||
Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
|
||||
//$table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // role id
|
||||
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
|
||||
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
|
||||
}
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
$table->timestamps();
|
||||
if ($teams || config('permission.testing')) {
|
||||
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
|
||||
} else {
|
||||
$table->unique(['name', 'guard_name']);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
|
||||
});
|
||||
|
||||
app('cache')
|
||||
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
|
||||
->forget(config('permission.cache.key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
if (empty($tableNames)) {
|
||||
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
|
||||
}
|
||||
|
||||
Schema::drop($tableNames['role_has_permissions']);
|
||||
Schema::drop($tableNames['model_has_roles']);
|
||||
Schema::drop($tableNames['model_has_permissions']);
|
||||
Schema::drop($tableNames['roles']);
|
||||
Schema::drop($tableNames['permissions']);
|
||||
}
|
||||
};
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('dag_events', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('dag_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('dag_run_id')->nullable()->constrained()->onDelete('cascade');
|
||||
$table->string('event_type'); // Тип события: 'failure', 'success', 'task_failed', и т.д.
|
||||
$table->text('message')->nullable(); // Дополнительное сообщение
|
||||
$table->json('metadata')->nullable(); // Дополнительные данные
|
||||
$table->timestamps(); // created_at будет временем события
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('dag_events');
|
||||
}
|
||||
};
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('task_instances', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('dag_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('dag_run_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('airflow_id')->after('dag_id')->constrained('airflows')->onDelete('cascade');
|
||||
$table->string('task_id'); // ID задачи в Airflow
|
||||
$table->enum('state', [
|
||||
'success',
|
||||
'running',
|
||||
'failed',
|
||||
'queued',
|
||||
'skipped',
|
||||
'up_for_retry',
|
||||
'upstream_failed',
|
||||
'up_for_reschedule',
|
||||
'none',
|
||||
])->nullable();
|
||||
$table->timestamp('execution_date')->nullable();
|
||||
$table->timestamp('start_date')->nullable();
|
||||
$table->timestamp('end_date')->nullable();
|
||||
$table->longText('log')->nullable(); // Логи выполнения задачи
|
||||
$table->json('metadata')->nullable(); // Дополнительные данные
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('task_instances');
|
||||
}
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,39 @@
|
||||
<div class="p-6 bg-white border border-gray-200 rounded-lg shadow">
|
||||
<div class="flex justify-between items-center">
|
||||
<h2 class="text-xl font-bold text-gray-900">
|
||||
Airflow Cluster: {{ $airflow->name }}
|
||||
</h2>
|
||||
<span class="text-sm text-gray-500">
|
||||
Updated at: {{ now()->format('H:i:s') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<p><strong>URL:</strong> <a href="{{ $airflow->url }}" class="text-blue-500" target="_blank">{{ $airflow->url }}</a></p>
|
||||
<p><strong>Version:</strong> {{ $airflow->version }}</p>
|
||||
<p><strong>Port:</strong> {{ $airflow->port }}</p>
|
||||
<p><strong>Status:</strong>
|
||||
<span class="px-2 py-1 rounded-full text-sm {{ $airflow->is_active ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' }}">
|
||||
{{ $airflow->is_active ? 'Active' : 'Inactive' }}
|
||||
</span>
|
||||
</p>
|
||||
<p><strong>Managed by:</strong> {{ $airflow->user->name }}</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800">DAGs in this cluster:</h3>
|
||||
<ul class="mt-2 list-disc list-inside">
|
||||
@foreach ($airflow->dags as $dag)
|
||||
<li>{{ $dag->name }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('livewire:load', function () {
|
||||
setInterval(() => {
|
||||
Livewire.emit('refreshData');
|
||||
}, 5000);
|
||||
});
|
||||
</script>
|
@ -0,0 +1,53 @@
|
||||
<div class="max-w-lg mx-auto p-6 bg-white rounded-lg shadow-lg">
|
||||
@if (session()->has('message'))
|
||||
<div class="mb-4 p-4 bg-green-100 text-green-700 rounded-lg">
|
||||
{{ session('message') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form wire:submit.prevent="submit" class="space-y-4">
|
||||
<div class="form-group">
|
||||
<label for="name" class="block text-gray-700 font-semibold">Name</label>
|
||||
<input type="text" id="name" wire:model="name" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
@error('name') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="url" class="block text-gray-700 font-semibold">URL</label>
|
||||
<input type="text" id="url" wire:model="url" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
@error('url') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="username" class="block text-gray-700 font-semibold">Username</label>
|
||||
<input type="text" id="username" wire:model="username" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
@error('username') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password" class="block text-gray-700 font-semibold">Password</label>
|
||||
<input type="password" id="password" wire:model="password" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
@error('password') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="api_token" class="block text-gray-700 font-semibold">API Token</label>
|
||||
<input type="text" id="api_token" wire:model="api_token" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
@error('api_token') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="port" class="block text-gray-700 font-semibold">Port</label>
|
||||
<input type="text" id="port" wire:model="port" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
@error('port') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="version" class="block text-gray-700 font-semibold">Version</label>
|
||||
<input type="text" id="version" wire:model="version" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
@error('version') <span class="text-red-500 text-sm">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<button type="submit" class="w-full bg-blue-500 text-white font-semibold py-2 px-4 rounded-lg hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50">Save</button>
|
||||
</form>
|
||||
</div>
|
@ -0,0 +1,33 @@
|
||||
<div class="bg-white shadow-lg rounded-xl p-6 overflow-hidden">
|
||||
@if(empty($data) || count($data) == 0)
|
||||
<div class="flex flex-col items-center justify-center">
|
||||
<svg class="w-16 h-16 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17v-2a4 4 0 00-4-4H3m18 0h-2a4 4 0 00-4 4v2m-4-4v6m4-6v6M7 17v6m10-6v6"/>
|
||||
</svg>
|
||||
<p class="text-gray-600 mt-4">Нет данных для отображения.</p>
|
||||
</div>
|
||||
@else
|
||||
<table class="min-w-full bg-gray-50 rounded-lg shadow-md">
|
||||
<thead class="bg-gradient-to-r from-gray-100 to-gray-200 text-gray-700">
|
||||
<tr>
|
||||
@foreach($headers as $header)
|
||||
<th class="px-6 py-4 text-left text-sm font-semibold text-gray-800 border-b border-gray-300">
|
||||
{{ $header }}
|
||||
</th>
|
||||
@endforeach
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-700">
|
||||
@foreach($data as $row)
|
||||
<tr class="bg-white hover:bg-gray-50 transition-colors shadow-sm hover:shadow-lg">
|
||||
@foreach($row as $cell)
|
||||
<td class="px-6 py-4 border-b border-gray-200 text-sm">
|
||||
{{ $cell }}
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endif
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
{{-- Stop trying to control. --}}
|
||||
</div>
|
@ -0,0 +1,19 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
AirFlow Clusters
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 flex space-x-4">
|
||||
<div class="w-1/3">
|
||||
<livewire:airflow-data-view :airflowId="$id" />
|
||||
</div>
|
||||
|
||||
<div class="w-2/3">
|
||||
HERE WAS A TABLE
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
@ -0,0 +1,19 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
AirFlow Clusters
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 flex space-x-4">
|
||||
<div class="w-1/3">
|
||||
<livewire:airflow-form />
|
||||
</div>
|
||||
|
||||
<div class="w-2/3">
|
||||
<livewire:air-flow-target-table />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
@ -0,0 +1,19 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
All Dags
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 flex space-x-4">
|
||||
<div class="w-1/3">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="w-2/3">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
@ -0,0 +1 @@
|
||||
<?php
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue