lasthourcloud/resources/views/components/magic-search-bar.blade.php

383 lines
17 KiB
PHP
Raw Normal View History

2023-05-12 09:17:56 +00:00
<div x-data="magicsearchbar" @slash.window="mainMenu = true">
2023-05-11 13:20:02 +00:00
{{-- Main --}}
2023-05-12 08:45:28 +00:00
<template x-cloak x-if="!serverMenu && !destinationMenu && !projectMenu && !environmentMenu">
<div>
2023-05-12 09:17:56 +00:00
<div class="mainMenu">
<input x-ref="search" x-model="search" class="w-96" x-on:click="checkMainMenu"
x-on:click.outside="closeMenus" placeholder="Search or jump to..." x-on:keyup.escape="clearSearch"
x-on:keyup.down="focusNext(items.length)" x-on:keyup.up="focusPrev(items.length)"
x-on:keyup.enter="await set('server',filteredItems()[focusedIndex].name)" />
</div>
2023-05-12 08:45:28 +00:00
<div x-cloak x-show="mainMenu" class="absolute text-sm top-11 w-[25rem] bg-neutral-800">
<template x-for="(item,index) in filteredItems" :key="item.name">
<div x-on:click="await set('server',item.name)" :class="focusedIndex === index && 'bg-neutral-700'"
:class="item.disabled &&
'text-neutral-500 bg-neutral-900 hover:bg-neutral-900 cursor-not-allowed opacity-60'"
class="py-2 pl-4 cursor-pointer hover:bg-neutral-700">
<span class="px-2 mr-1 text-xs bg-green-600 rounded" x-show="item.type === 'Add'"
x-text="item.type"></span>
<span class="px-2 mr-1 text-xs bg-purple-600 rounded" x-show="item.type === 'Jump'"
x-text="item.type"></span>
<span x-text="item.name"></span>
</div>
</template>
2023-05-10 17:26:28 +00:00
</div>
2023-05-12 08:45:28 +00:00
</div>
</template>
2023-05-11 13:20:02 +00:00
{{-- Servers --}}
2023-05-12 08:45:28 +00:00
<template x-cloak x-if="serverMenu">
<div x-on:click.outside="closeMenus">
<input x-ref="search" x-model="search" class="w-96" placeholder="Select a server..."
x-on:keyup.down="focusNext(servers.length)" x-on:keyup.up="focusPrev(servers.length)"
x-on:keyup.enter="await set('destination',filteredServers()[focusedIndex].uuid)" />
<div class="absolute text-sm top-11 w-[25rem] bg-neutral-800">
<template x-for="(server,index) in filteredServers" :key="server.name ?? server">
<div x-on:click="await set('destination',server.uuid)"
:class="focusedIndex === index && 'bg-neutral-700'"
class="py-2 pl-4 cursor-pointer hover:bg-neutral-700">
<span class="px-2 mr-1 text-xs bg-purple-600 rounded">Server</span>
<span x-text="server.name"></span>
</div>
</template>
</div>
2023-05-11 13:20:02 +00:00
</div>
2023-05-12 08:45:28 +00:00
</template>
2023-05-11 13:20:02 +00:00
{{-- Destinations --}}
2023-05-12 08:45:28 +00:00
<template x-cloak x-if="destinationMenu">
<div x-on:click.outside="closeMenus">
<input x-ref="search" x-model="search" class="w-96" placeholder="Select a destination..."
x-on:keyup.down="focusNext(destinations.length)" x-on:keyup.up="focusPrev(destinations.length)"
x-on:keyup.enter="await set('project',filteredDestinations()[focusedIndex].uuid)" />
<div class="absolute text-sm top-11 w-[25rem] bg-neutral-800">
<template x-for="(destination,index) in filteredDestinations" :key="destination.name ?? destination">
<div x-on:click="await set('project',destination.uuid)"
:class="focusedIndex === index && 'bg-neutral-700'"
class="py-2 pl-4 cursor-pointer hover:bg-neutral-700">
<span class="px-2 mr-1 text-xs bg-purple-700 rounded">Destination</span>
<span x-text="destination.name"></span>
</div>
</template>
</div>
2023-05-11 13:20:02 +00:00
</div>
2023-05-12 08:45:28 +00:00
</template>
2023-05-11 13:20:02 +00:00
{{-- Projects --}}
2023-05-12 08:45:28 +00:00
<template x-cloak x-if="projectMenu">
<div x-on:click.outside="closeMenus">
<input x-ref="search" x-model="search" class="w-96" placeholder="Type your project name..."
x-on:keyup.down="focusNext(projects.length + 1)" x-on:keyup.up="focusPrev(projects.length + 1)"
x-on:keyup.enter="await set('environment',filteredProjects()[focusedIndex - 1]?.uuid)" />
<div class="absolute text-sm top-11 w-[25rem] bg-neutral-800">
<div x-on:click="await newProject" class="py-2 pl-4 cursor-pointer hover:bg-neutral-700"
:class="focusedIndex === 0 && 'bg-neutral-700'">
<span>New Project</span>
<span x-text="search"></span>
2023-05-11 13:20:02 +00:00
</div>
2023-05-12 08:45:28 +00:00
<template x-for="(project,index) in filteredProjects" :key="project.name ?? project">
<div x-on:click="await set('environment',project.uuid)"
:class="focusedIndex === index + 1 && 'bg-neutral-700'"
class="py-2 pl-4 cursor-pointer hover:bg-neutral-700">
<span class="px-2 mr-1 text-xs bg-purple-700 rounded">Project</span>
<span x-text="project.name"></span>
</div>
</template>
</div>
2023-05-11 13:20:02 +00:00
</div>
2023-05-12 08:45:28 +00:00
</template>
2023-05-11 13:20:02 +00:00
{{-- Environments --}}
2023-05-12 08:45:28 +00:00
<template x-cloak x-if="environmentMenu">
<div x-on:click.outside="closeMenus">
<input x-ref="search" x-model="search" class="w-96" placeholder="Select a environment..."
x-on:keyup.down="focusNext(environments.length + 1)" x-on:keyup.up="focusPrev(environments.length + 1)"
x-on:keyup.enter="await set('jump',filteredEnvironments()[focusedIndex - 1]?.name)" />
<div class="absolute text-sm top-11 w-[25rem] bg-neutral-800">
<div x-on:click="await newEnvironment" class="py-2 pl-4 cursor-pointer hover:bg-neutral-700"
:class="focusedIndex === 0 && 'bg-neutral-700'">
<span>New Environment</span>
<span x-text="search"></span>
2023-05-11 13:20:02 +00:00
</div>
2023-05-12 08:45:28 +00:00
<template x-for="(environment,index) in filteredEnvironments" :key="environment.name ?? environment">
<div x-on:click="await set('jump',environment.name)"
:class="focusedIndex === index + 1 && 'bg-neutral-700'"
class="py-2 pl-4 cursor-pointer hover:bg-neutral-700">
<span class="px-2 mr-1 text-xs bg-purple-700 rounded">Env</span>
<span x-text="environment.name"></span>
</div>
</template>
</div>
2023-05-11 13:20:02 +00:00
</div>
2023-05-12 08:45:28 +00:00
</template>
2023-05-10 17:26:28 +00:00
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('magicsearchbar', () => ({
2023-05-12 08:45:28 +00:00
focus() {
if (this.$refs.search) this.$refs.search.focus()
},
2023-05-11 13:20:02 +00:00
init() {
2023-05-12 08:45:28 +00:00
this.$watch('search', () => {
this.focusedIndex = ""
})
this.$watch('mainMenu', () => {
this.focus()
2023-05-11 13:20:02 +00:00
})
2023-05-12 08:45:28 +00:00
this.$watch('serverMenu', () => {
this.focus()
2023-05-11 13:20:02 +00:00
})
2023-05-12 08:45:28 +00:00
this.$watch('destinationMenu', () => {
this.focus()
2023-05-11 13:20:02 +00:00
})
2023-05-12 08:45:28 +00:00
this.$watch('projectMenu', () => {
this.focus()
2023-05-11 13:20:02 +00:00
})
2023-05-12 08:45:28 +00:00
this.$watch('environmentMenu', () => {
this.focus()
2023-05-11 13:20:02 +00:00
})
},
mainMenu: false,
serverMenu: false,
destinationMenu: false,
projectMenu: false,
environmentMenu: false,
2023-05-12 08:45:28 +00:00
search: '',
2023-05-11 13:20:02 +00:00
selectedAction: '',
selectedServer: '',
selectedDestination: '',
selectedProject: '',
selectedEnvironment: '',
servers: ['Loading...'],
destinations: ['Loading...'],
projects: ['Loading...'],
environments: ['Loading...'],
2023-05-12 08:45:28 +00:00
focusedIndex: "",
2023-05-10 17:26:28 +00:00
items: [{
2023-05-11 13:20:02 +00:00
name: 'Public Repository',
type: 'Add',
tags: 'application,public,repository',
},
{
name: 'Private Repository (with GitHub App)',
type: 'Add',
tags: 'application,private,repository',
},
{
name: 'Private Repository (with Deploy Key)',
type: 'Add',
tags: 'application,private,repository',
},
{
name: 'Database',
type: 'Add',
tags: 'data,database,mysql,postgres,sql,sqlite,redis,mongodb,maria,percona',
disabled: true,
},
{
name: 'Servers',
type: 'Jump',
}
],
2023-05-12 08:45:28 +00:00
focusPrev(maxLength) {
if (this.focusedIndex === "") {
this.focusedIndex = maxLength - 1
} else {
if (this.focusedIndex > 0) {
this.focusedIndex = this.focusedIndex - 1
}
}
2023-05-11 13:20:02 +00:00
},
2023-05-12 08:45:28 +00:00
focusNext(maxLength) {
if (this.focusedIndex === "") {
this.focusedIndex = 0
} else {
if (maxLength > this.focusedIndex + 1) {
this.focusedIndex = this.focusedIndex + 1
}
}
2023-05-11 13:20:02 +00:00
},
2023-05-12 09:17:56 +00:00
clearSearch() {
if (this.search === '') {
this.closeMenus()
this.$nextTick(() => {
this.$refs.search.blur();
})
return
}
this.search = ''
this.focusedIndex = ''
},
2023-05-12 08:45:28 +00:00
closeMenus() {
2023-05-12 09:17:56 +00:00
this.search = ''
2023-05-12 08:45:28 +00:00
this.focusedIndex = ''
this.mainMenu = false
2023-05-11 13:20:02 +00:00
this.serverMenu = false
this.destinationMenu = false
this.projectMenu = false
this.environmentMenu = false
2023-05-12 08:45:28 +00:00
},
checkMainMenu() {
if (this.serverMenu) return
this.mainMenu = true
2023-05-10 17:26:28 +00:00
},
filteredItems() {
2023-05-12 08:45:28 +00:00
if (this.search === '') return this.items
2023-05-10 17:26:28 +00:00
return this.items.filter(item => {
2023-05-12 08:45:28 +00:00
return item.name.toLowerCase().includes(this.search.toLowerCase())
2023-05-11 13:20:02 +00:00
})
},
filteredServers() {
2023-05-12 08:45:28 +00:00
if (this.search === '') return this.servers
2023-05-11 13:20:02 +00:00
return this.servers.filter(server => {
2023-05-12 08:45:28 +00:00
return server.name.toLowerCase().includes(this.search
2023-05-11 13:20:02 +00:00
.toLowerCase())
})
},
filteredDestinations() {
2023-05-12 08:45:28 +00:00
if (this.search === '') return this.destinations
2023-05-11 13:20:02 +00:00
return this.destinations.filter(destination => {
2023-05-12 08:45:28 +00:00
return destination.name.toLowerCase().includes(this.search
2023-05-11 13:20:02 +00:00
.toLowerCase())
2023-05-10 17:26:28 +00:00
})
},
2023-05-11 13:20:02 +00:00
filteredProjects() {
2023-05-12 08:45:28 +00:00
if (this.search === '') return this.projects
2023-05-11 13:20:02 +00:00
return this.projects.filter(project => {
2023-05-12 08:45:28 +00:00
return project.name.toLowerCase().includes(this.search
2023-05-11 13:20:02 +00:00
.toLowerCase())
})
},
filteredEnvironments() {
2023-05-12 08:45:28 +00:00
if (this.search === '') return this.environments
2023-05-11 13:20:02 +00:00
return this.environments.filter(environment => {
2023-05-12 08:45:28 +00:00
return environment.name.toLowerCase().includes(this.search
2023-05-11 13:20:02 +00:00
.toLowerCase())
})
},
async newProject() {
const response = await fetch('/magic?server=' + this.selectedServer +
'&destination=' + this.selectedDestination +
2023-05-12 08:45:28 +00:00
'&project=new&name=' + this.search);
2023-05-11 13:20:02 +00:00
if (response.ok) {
const {
project_uuid
} = await response.json();
2023-05-12 08:45:28 +00:00
this.set('environment', project_uuid)
this.set('jump', 'production')
2023-05-11 13:20:02 +00:00
}
},
async newEnvironment() {
const response = await fetch('/magic?server=' + this.selectedServer +
'&destination=' + this.selectedDestination +
'&project=' + this.selectedProject + '&environment=new&name=' + this
2023-05-12 08:45:28 +00:00
.search);
2023-05-11 13:20:02 +00:00
if (response.ok) {
2023-05-12 08:45:28 +00:00
const {
environment_name
} = await response.json();
this.set('jump', environment_name)
2023-05-11 13:20:02 +00:00
}
},
2023-05-12 08:45:28 +00:00
async set(action, id) {
2023-05-11 13:20:02 +00:00
let response = null
2023-05-10 17:26:28 +00:00
switch (action) {
2023-05-11 13:20:02 +00:00
case 'server':
this.items.find((item, index) => {
if (item.name.toLowerCase() === id
.toLowerCase()) {
return this.selectedAction = index
}
})
response = await fetch('/magic?servers=true');
if (response.ok) {
const {
servers
} = await response.json();
this.servers = servers;
}
2023-05-12 08:45:28 +00:00
this.closeMenus()
this.serverMenu = true
2023-05-10 17:26:28 +00:00
break
2023-05-11 13:20:02 +00:00
case 'destination':
2023-05-12 08:45:28 +00:00
this.selectedServer = id
2023-05-11 13:20:02 +00:00
if (this.items[this.selectedAction].type === "Jump") {
return window.location = '/server/' + id
}
response = await fetch('/magic?server=' + this
.selectedServer +
'&destinations=true');
if (response.ok) {
const {
destinations
} = await response.json();
this.destinations = destinations;
}
2023-05-12 08:45:28 +00:00
this.closeMenus()
this.destinationMenu = true
2023-05-10 17:26:28 +00:00
break
2023-05-11 13:20:02 +00:00
case 'project':
this.selectedDestination = id
response = await fetch('/magic?server=' + this
.selectedServer +
'&destination=' + this.selectedDestination +
'&projects=true');
if (response.ok) {
const {
projects
} = await response.json();
this.projects = projects;
}
2023-05-12 08:45:28 +00:00
this.closeMenus()
this.projectMenu = true
2023-05-10 17:26:28 +00:00
break
2023-05-11 13:20:02 +00:00
case 'environment':
2023-05-12 08:45:28 +00:00
if (this.focusedIndex === 0) {
this.focusedIndex = ''
return await this.newProject()
}
2023-05-11 13:20:02 +00:00
2023-05-12 08:45:28 +00:00
this.selectedProject = id
2023-05-11 13:20:02 +00:00
response = await fetch('/magic?server=' + this
.selectedServer +
'&destination=' + this.selectedDestination +
'&project=' + this
.selectedProject + '&environments=true');
if (response.ok) {
const {
environments
} = await response.json();
this.environments = environments;
}
2023-05-12 08:45:28 +00:00
this.closeMenus()
this.environmentMenu = true
2023-05-11 13:20:02 +00:00
break
case 'jump':
2023-05-12 08:45:28 +00:00
if (this.focusedIndex === 0) {
this.focusedIndex = ''
return await this.newEnvironment()
}
2023-05-11 13:20:02 +00:00
this.selectedEnvironment = id
if (this.selectedAction === 0) {
window.location =
`/project/${this.selectedProject}/${this.selectedEnvironment}/new?type=public&destination=${this.selectedDestination}`
} else if (this.selectedAction === 1) {
window.location =
`/project/${this.selectedProject}/${this.selectedEnvironment}/new?type=private-gh-app&destination=${this.selectedDestination}`
} else if (this.selectedAction === 2) {
window.location =
`/project/${this.selectedProject}/${this.selectedEnvironment}/new?type=private-deploy-key&destination=${this.selectedDestination}`
} else if (this.selectedAction === 3) {
console.log('new Database')
}
2023-05-12 08:45:28 +00:00
this.closeMenus()
2023-05-10 17:26:28 +00:00
break
}
}
}))
})
</script>