This commit is contained in:
Andras Bacsai 2023-06-16 15:01:58 +02:00
parent 66af4d98ce
commit b948457115
14 changed files with 167 additions and 42 deletions

View File

@ -6,6 +6,7 @@
use App\Models\Environment;
use App\Models\Project;
use App\Models\Server;
use App\Models\Team;
class MagicController extends Controller
{
@ -53,4 +54,16 @@ public function newEnvironment()
'environment_name' => $environment->name,
]);
}
public function newTeam()
{
$team = Team::create(
[
'name' => request()->query('name') ?? generate_random_name(),
'personal_team' => false,
],
);
auth()->user()->teams()->attach($team, ['role' => 'admin']);
session(['currentTeam' => $team]);
return redirect(request()->header('Referer'));
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace App\Http\Livewire\Team;
use App\Models\Team;
use Livewire\Component;
class Create extends Component
{
public string $name = '';
public string|null $description = null;
protected $rules = [
'name' => 'required|min:3|max:255',
'description' => 'nullable|min:3|max:255',
];
protected $validationAttributes = [
'name' => 'name',
'description' => 'description',
];
public function submit()
{
$this->validate();
try {
$team = Team::create([
'name' => $this->name,
'description' => $this->description,
'personal_team' => false,
]);
auth()->user()->teams()->attach($team, ['role' => 'admin']);
session(['currentTeam' => $team]);
return redirect()->route('team.show');
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Http\Livewire\Team;
use App\Models\Team;
use Livewire\Component;
use Masmerise\Toaster\Toaster;
class Form extends Component
{
public Team $team;
protected $rules = [
'team.name' => 'required|min:3|max:255',
'team.description' => 'nullable|min:3|max:255',
];
protected $validationAttributes = [
'team.name' => 'name',
'team.description' => 'description',
];
public function mount()
{
$this->team = session('currentTeam');
}
public function submit()
{
$this->validate();
try {
$this->team->save();
session(['currentTeam' => $this->team]);
$this->emit('reloadWindow');
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
}

View File

@ -20,6 +20,7 @@ class Team extends Model implements SendsDiscord, SendsEmail
protected $fillable = [
'id',
'name',
'description',
'personal_team',
'extra_attributes',
];

View File

@ -14,6 +14,7 @@ public function up(): void
Schema::create('teams', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('description')->nullable();
$table->boolean('personal_team')->default(false);
$table->schemalessAttributes('extra_attributes');
$table->timestamps();

View File

@ -5,7 +5,6 @@
use App\Models\Team;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class TeamSeeder extends Seeder
{
@ -13,6 +12,8 @@ public function run(): void
{
$normal_user_in_root_team = User::find(1);
$root_user_personal_team = Team::find(0);
$root_user_personal_team->description = 'The root team';
$root_user_personal_team->save();
$normal_user_in_root_team->teams()->attach($root_user_personal_team);

View File

@ -293,75 +293,82 @@ const magicActions = [{
new: true,
sequence: ['main', 'server', 'redirect']
},
{
id: 8,
name: 'Create: Team',
icon: '/',
sequence: ['main', 'redirect']
},
{
id: 9,
name: 'Goto: Dashboard',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 9,
id: 10,
name: 'Goto: Servers',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 10,
id: 11,
name: 'Goto: Private Keys',
tags: 'destination,docker,network,new,create',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 11,
id: 12,
name: 'Goto: Projects',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 12,
id: 13,
name: 'Goto: Sources',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 13,
id: 14,
name: 'Goto: Destinations',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 14,
id: 15,
name: 'Goto: Settings',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 15,
id: 16,
name: 'Goto: Command Center',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 16,
id: 17,
name: 'Goto: Notifications',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 17,
id: 18,
name: 'Goto: Profile',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 18,
id: 19,
name: 'Goto: Teams',
icon: 'goto',
sequence: ['main', 'redirect']
},
{
id: 19,
id: 20,
name: 'Goto: Switch Teams',
icon: 'goto',
sequence: ['main', 'redirect']
@ -546,40 +553,43 @@ async function redirect() {
targetUrl.searchParams.append('server', server)
break;
case 8:
targetUrl.pathname = `/`
targetUrl.pathname = `/team/new`
break;
case 9:
targetUrl.pathname = `/servers`
targetUrl.pathname = `/`
break;
case 10:
targetUrl.pathname = `/private-keys`
targetUrl.pathname = `/servers`
break;
case 11:
targetUrl.pathname = `/projects`
targetUrl.pathname = `/private-keys`
break;
case 12:
targetUrl.pathname = `/sources`
targetUrl.pathname = `/projects`
break;
case 13:
targetUrl.pathname = `/destinations`
targetUrl.pathname = `/sources`
break;
case 14:
targetUrl.pathname = `/settings`
targetUrl.pathname = `/destinations`
break;
case 15:
targetUrl.pathname = `/command-center`
targetUrl.pathname = `/settings`
break;
case 16:
targetUrl.pathname = `/profile/team/notifications`
targetUrl.pathname = `/command-center`
break;
case 17:
targetUrl.pathname = `/profile`
targetUrl.pathname = `/team/notifications`
break;
case 18:
targetUrl.pathname = `/profile/team`
targetUrl.pathname = `/profile`
break;
case 19:
targetUrl.pathname = `/profile/team`
targetUrl.pathname = `/team`
break;
case 20:
targetUrl.pathname = `/team`
break;
}
window.location.href = targetUrl;

View File

@ -100,7 +100,8 @@ class="absolute top-0 right-0 p-2 m-2 my-1 cursor-pointer hover:bg-transparent h
</a>
</li>
<li>
<a class="text-white rounded-none hover:no-underline hover:bg-coollabs" href="/profile/team">
<a class="text-white rounded-none hover:no-underline hover:bg-coollabs"
href="{{ route('team.show') }}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">
@ -117,7 +118,7 @@ class="absolute top-0 right-0 p-2 m-2 my-1 cursor-pointer hover:bg-transparent h
<form action="/logout" method="POST">
<li>
@csrf
<button class=" text-white rounded-none hover:bg-coollabs"> <svg
<button class="text-white rounded-none hover:bg-coollabs"> <svg
xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
stroke-linejoin="round">

View File

@ -1,26 +1,26 @@
<div class="pb-6">
<h1>Team</h1>
<nav class="flex pt-2 pb-10 ">
<nav class="flex pt-2 pb-10">
<ol class="inline-flex items-center">
<li class="inline-flex items-center">
Currently Active Team
</li>
<li>
<div class="flex items-center">
<svg aria-hidden="true" class="w-4 h-4 mx-1 font-bold text-warning" fill="currentColor"
viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"></path>
</svg>
<span class="font-bold text-warning">{{ session('currentTeam.name') }}</span>
<span>Currently active team: {{ session('currentTeam.name') }}</span>
</div>
</li>
<li class="inline-flex items-center">
<svg aria-hidden="true" class="w-4 h-4 mx-1 font-bold text-warning" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"></path>
</svg>
<span class="truncate">{{ Str::limit(session('currentTeam.description'), 52) }}</span>
</li>
</ol>
</nav>
<nav class="flex items-end gap-4 py-2 border-b-2 border-solid border-coolgray-200">
<a class="{{ request()->routeIs('team.show') ? 'text-white' : '' }}" href="{{ route('team.show') }}">
<button>Members</button>
<button>General</button>
</a>
<a class="{{ request()->routeIs('team.notifications') ? 'text-white' : '' }}"
href="{{ route('team.notifications') }}">

View File

@ -0,0 +1,7 @@
<form class="flex flex-col gap-2" wire:submit.prevent='submit'>
<x-forms.input autofocus id="name" label="Name" required />
<x-forms.input id="description" label="Description" />
<x-forms.button type="submit">
Save Team
</x-forms.button>
</form>

View File

@ -0,0 +1,12 @@
<form class="flex flex-col gap-2 pb-6" wire:submit.prevent='submit'>
<div class="flex items-end gap-2">
<h2>General</h2>
<x-forms.button type="submit">
Save
</x-forms.button>
</div>
<div class="flex gap-2">
<x-forms.input id="team.name" label="Name" required />
<x-forms.input id="team.description" label="Description" />
</div>
</form>

View File

@ -0,0 +1,5 @@
<x-layout>
<h1>New Team</h1>
<div class="pt-2 pb-10">Add a new team</div>
<livewire:team.create />
</x-layout>

View File

@ -1,7 +1,8 @@
<x-layout>
<x-team.navbar :team="session('currentTeam')" />
<h2>Members</h2>
<div class="overflow-hidden">
<livewire:team.form />
<h3>Members</h3>
<div class="pt-4 overflow-hidden">
<table>
<thead>
<tr>

View File

@ -90,8 +90,9 @@
Route::get('/settings', [Controller::class, 'settings'])->name('settings.configuration');
Route::get('/settings/emails', [Controller::class, 'emails'])->name('settings.emails');
Route::get('/profile', fn () => view('profile', ['request' => request()]))->name('profile');
Route::get('/profile/team', [Controller::class, 'team'])->name('team.show');
Route::get('/profile/team/notifications', fn () => view('team.notifications'))->name('team.notifications');
Route::get('/team', [Controller::class, 'team'])->name('team.show');
Route::get('/team/new', fn () => view('team.create'))->name('team.create');
Route::get('/team/notifications', fn () => view('team.notifications'))->name('team.notifications');
Route::get('/command-center', fn () => view('command-center', ['servers' => Server::validated()->get()]))->name('command-center');
Route::get('/invitations/{uuid}', [Controller::class, 'acceptInvitation'])->name('team.invitation.accept');
Route::get('/invitations/{uuid}/revoke', [Controller::class, 'revokeInvitation'])->name('team.invitation.revoke');