feat: project search on frontend
This commit is contained in:
@@ -24,6 +24,8 @@ class Project extends BaseModel
|
|||||||
{
|
{
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
protected $appends = ['default_environment'];
|
||||||
|
|
||||||
public static function ownedByCurrentTeam()
|
public static function ownedByCurrentTeam()
|
||||||
{
|
{
|
||||||
return Project::whereTeamId(currentTeam()->id)->orderBy('name');
|
return Project::whereTeamId(currentTeam()->id)->orderBy('name');
|
||||||
@@ -131,7 +133,7 @@ class Project extends BaseModel
|
|||||||
return $this->postgresqls()->get()->merge($this->redis()->get())->merge($this->mongodbs()->get())->merge($this->mysqls()->get())->merge($this->mariadbs()->get())->merge($this->keydbs()->get())->merge($this->dragonflies()->get())->merge($this->clickhouses()->get());
|
return $this->postgresqls()->get()->merge($this->redis()->get())->merge($this->mongodbs()->get())->merge($this->mysqls()->get())->merge($this->mariadbs()->get())->merge($this->keydbs()->get())->merge($this->dragonflies()->get())->merge($this->clickhouses()->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function default_environment()
|
public function getDefaultEnvironmentAttribute()
|
||||||
{
|
{
|
||||||
$default = $this->environments()->where('name', 'production')->first();
|
$default = $this->environments()->where('name', 'production')->first();
|
||||||
if ($default) {
|
if ($default) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<div class="grid grid-cols-1 gap-2 xl:grid-cols-2">
|
<div class="grid grid-cols-1 gap-2 xl:grid-cols-2">
|
||||||
@foreach ($projects as $project)
|
@foreach ($projects as $project)
|
||||||
<div class="gap-2 border border-transparent cursor-pointer box group"
|
<div class="gap-2 border border-transparent cursor-pointer box group"
|
||||||
onclick="gotoProject('{{ $project->uuid }}','{{ $project->default_environment() }}')">
|
onclick="gotoProject('{{ $project->uuid }}','{{ $project->default_environment }}')">
|
||||||
<div class="flex flex-1 mx-6">
|
<div class="flex flex-1 mx-6">
|
||||||
<div class="flex flex-col justify-center flex-1">
|
<div class="flex flex-col justify-center flex-1">
|
||||||
<div class="box-title">{{ $project->name }}</div>
|
<div class="box-title">{{ $project->name }}</div>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-center gap-2 text-xs font-bold">
|
<div class="flex items-center justify-center gap-2 text-xs font-bold">
|
||||||
<a class="hover:underline"
|
<a class="hover:underline"
|
||||||
href="{{ route('project.resource.create', ['project_uuid' => $project->uuid, 'environment_name' => data_get($project, 'default_environment()', 'production')]) }}">
|
href="{{ route('project.resource.create', ['project_uuid' => $project->uuid, 'environment_name' => data_get($project, 'default_environment', 'production')]) }}">
|
||||||
<span class="p-2 font-bold">+ Add Resource</span>
|
<span class="p-2 font-bold">+ Add Resource</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="hover:underline"
|
<a class="hover:underline"
|
||||||
|
|||||||
@@ -9,35 +9,59 @@
|
|||||||
</x-modal-input>
|
</x-modal-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="subtitle">All your projects are here.</div>
|
<div class="subtitle">All your projects are here.</div>
|
||||||
<div class="grid gap-2 lg:grid-cols-2">
|
<div x-data="searchComponent()">
|
||||||
@forelse ($projects as $project)
|
<x-forms.input placeholder="Search for name, description..." x-model="search" id="null" />
|
||||||
<div class="box group" onclick="gotoProject('{{ $project->uuid }}', '{{ $project->default_environment() }}')">
|
<div class="grid grid-cols-2 gap-4 pt-4">
|
||||||
|
<template x-if="allFilteredItems.length === 0">
|
||||||
|
<div>No project found with the search term "<span x-text="search"></span>".</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template x-for="item in allFilteredItems" :key="item.uuid">
|
||||||
|
<div class="box group" @click="gotoProject(item)">
|
||||||
<div class="flex flex-col justify-center flex-1 mx-6">
|
<div class="flex flex-col justify-center flex-1 mx-6">
|
||||||
<div class="box-title">{{ $project->name }}</div>
|
<div class="box-title" x-text="item.name"></div>
|
||||||
<div class="box-description ">
|
<div class="box-description ">
|
||||||
{{ $project->description }}</div>
|
<div x-text="item.description"></div>
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-center gap-2 pt-4 pb-2 mr-4 text-xs lg:py-0 lg:justify-normal">
|
|
||||||
<a class="mx-4 font-bold hover:underline"
|
|
||||||
href="{{ route('project.edit', ['project_uuid' => data_get($project, 'uuid')]) }}">
|
|
||||||
Settings
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@empty
|
|
||||||
<div>
|
|
||||||
<div>No project found.</div>
|
|
||||||
</div>
|
</div>
|
||||||
@endforelse
|
</template>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function gotoProject(uuid, environment) {
|
function sortFn(a, b) {
|
||||||
if (environment) {
|
return a.name.localeCompare(b.name)
|
||||||
window.location.href = '/project/' + uuid + '/' + environment;
|
}
|
||||||
|
|
||||||
|
function searchComponent() {
|
||||||
|
return {
|
||||||
|
search: '',
|
||||||
|
projects: @js($projects),
|
||||||
|
filterAndSort(items) {
|
||||||
|
if (this.search === '') {
|
||||||
|
return Object.values(items).sort(sortFn);
|
||||||
|
}
|
||||||
|
const searchLower = this.search.toLowerCase();
|
||||||
|
return Object.values(items).filter(item => {
|
||||||
|
return (item.name?.toLowerCase().includes(searchLower) ||
|
||||||
|
item.description?.toLowerCase().includes(searchLower))
|
||||||
|
}).sort(sortFn);
|
||||||
|
},
|
||||||
|
get allFilteredItems() {
|
||||||
|
return [
|
||||||
|
this.projects,
|
||||||
|
].flatMap((items) => this.filterAndSort(items));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoProject(item) {
|
||||||
|
if (item.default_environment) {
|
||||||
|
window.location.href = '/project/' + item.uuid + '/' + item.default_environment;
|
||||||
} else {
|
} else {
|
||||||
window.location.href = '/project/' + uuid;
|
window.location.href = '/project/' + item.uuid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -50,6 +50,10 @@
|
|||||||
<div x-data="searchComponent()">
|
<div x-data="searchComponent()">
|
||||||
<x-forms.input placeholder="Search for name, fqdn..." x-model="search" id="null" />
|
<x-forms.input placeholder="Search for name, fqdn..." x-model="search" id="null" />
|
||||||
<div class="grid grid-cols-1 gap-4 pt-4 lg:grid-cols-2 xl:grid-cols-3">
|
<div class="grid grid-cols-1 gap-4 pt-4 lg:grid-cols-2 xl:grid-cols-3">
|
||||||
|
<template x-if="allFilteredItems.length === 0">
|
||||||
|
<div>No resource found with the search term "<span x-text="search"></span>".</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template x-for="item in allFilteredItems" :key="item.uuid">
|
<template x-for="item in allFilteredItems" :key="item.uuid">
|
||||||
<span>
|
<span>
|
||||||
<a class="h-24 box group" :href="item.hrefLink">
|
<a class="h-24 box group" :href="item.hrefLink">
|
||||||
|
|||||||
Reference in New Issue
Block a user