Commit 1544861b authored by gj4210's avatar gj4210 👽
Browse files

ADD: Global Search

warning: broken mess atm
+ also changed ''API-Tokens" to "Accounts & Tokens"
parent 36a7a677
Pipeline #105455 passed with stages
in 7 minutes and 32 seconds
<template>
<b-form inline @submit="searchAction" class="mr-2">
<transition name="slide">
<b-form-group v-if="show_search || ($refs.navdropdown && $refs.navdropdown.show)">
<b-form-input
size="sm" placeholder="Suche" id="search" ref="search"
v-model="search_input" class="mr-2 search"
@focus="search_has_focus = true"
@blur="search_has_focus = false"
/>
<b-button class="search-clear bg-transparent" size="sm" v-if="search_input !== ''"
@click="search_input = ''">
<font-awesome-icon :icon="['fas','times']" class="text-secondary"/>
</b-button>
</b-form-group>
</transition>
<b-popover custom-class="popover-wide suggestions-popover shadow"
:show="search_input !== '' && search_has_focus"
target="search" placement="bottom">
<div class="suggestions-wrapper">
<div v-for="(suggestion, index) in suggestions"
:key="'search-suggestion-' + index"
class="suggestion p-3"
@click="suggestionClicked(suggestion)">
<font-awesome-icon class="text-secondary mr-2 suggestion-icon"
:icon="suggestion.type === 'page' ? 'link': 'question'"/>
<font-awesome-icon class="text-primary mr-2 suggestion-arrow" :icon="['fas', 'arrow-right']"/>
<b>{{ suggestion.name[0] }}</b>{{ suggestion.name[1] }}<b>{{ suggestion.name[2] }}</b>
</div>
<div v-if="suggestions && suggestions.length === 0"
class="font-italic text-center p-3">
Keine Ergebnisse
</div>
</div>
</b-popover>
<b-button class="search-button" size="sm" @click="searchAction"
:variant="search_input === '' ? 'secondary' : 'success'">
<font-awesome-icon :icon="['fas','search']"/>
</b-button>
<div class="search-cover-wrapper">
<div class="search-cover"/>
</div>
</b-form>
</template>
<script>
export default {
name: "GlobalSearch",
data() {
return {
show_search: false,
search_input: '',
search_has_focus: false,
pages: [
{
'name': 'DNSVS',
'url': '/dnsvs'
},
{
'name': 'BCDs',
'url': '/dnsvs/bcds'
},
{
'name': 'Accounts & Tokens',
'url': '/user/tokens'
},
{
'name': 'API (Swagger)',
'url': '/swagger'
},
{
'name': 'MACAuth',
'url': '/macauth'
},
],
test_search_terms: [
'Easter Egg',
'00:DE:AD:BE:EF:00',
'127.0.0.1',
'100.124.99.212:25565',
'Internet ist kaputt :(',
'Wörter ausdenken ist mein Job.',
'Sinn des Lebens',
'Funktioniert die Suche überhaupt?',
'Irgendwann wird Alles hier ersetzt.',
'Lorem Ipsum',
'What is love?',
'Minecraft XOR Gate Redstone Tutorial',
'Fortnite Epic Gamer Moments',
'Where can I buy Gamer Girl Bathwater?',
'How to fix ID-10-T error?',
'12345678?',
'Is password a good password?',
'Why my pc hacked?',
'VIRUS HELP',
'Why does my Windows support guy sound like his name is not George Smith?',
'scc.fail',
'Why internet not work?',
'Help',
'hellooooo?'
],
suggestion_hover: []
}
},
computed: {
suggestions() {
let suggestions = []
this.pages.forEach(page => {
let index = page.name.toLowerCase().indexOf(this.search_input.toLowerCase())
if (index !== -1) {
suggestions.push({
'name':
[page.name.substring(0, index),
page
.name.substring(index, index + this.search_input.length),
page
.name.substring(index + this.search_input.length)
],
'type': 'page',
'url': page.url
})
}
}
)
this.test_search_terms.forEach(term => {
let index = term.toLowerCase().indexOf(this.search_input.toLowerCase())
if (index !== -1) {
suggestions.push({
'name':
[term.substring(0, index),
term
.substring(index, index + this.search_input.length),
term
.substring(index + this.search_input.length)
],
'type': 'test'
})
}
})
return suggestions
}
},
methods: {
searchAction(e) {
e.preventDefault()
if (this.search_input === '') {
this.show_search = !this.show_search
if (this.show_search) {
this.$nextTick(() => {
this.$refs.search.focus()
})
}
} else {
// TODO: actually search stuff
window.console.log('Search: ' + this.search_input)
this.search_input = ''
}
},
suggestionClicked(suggestion) {
if (suggestion.type === 'page' && this.$router.currentRoute !== suggestion.url) {
this.$router.push(suggestion.url)
}
if (suggestion.type === 'test') {
window.console.log('Clicked test suggestion: ' + suggestion.name[0] + suggestion.name[1] + suggestion.name[2])
}
}
}
}
</script>
<style scoped>
.slide-enter-active,
.slide-leave-active {
transition: transform 250ms;
z-index: -10;
}
.slide-enter,
.slide-leave-to {
transform: translateX(120%);
}
.search-cover-wrapper {
position: relative;
width: 0;
height: 0;
}
.search-cover {
z-index: -1;
position: absolute;
left: -30px;
top: -25px;
width: 300px;
height: 50px;
background: #343A40;
}
.search {
max-width: 250px;
}
.search-button {
z-index: 1;
}
.suggestions-popover {
width: 300px;
max-height: 75vh;
overflow-y: scroll;
}
.suggestions-popover::-webkit-scrollbar {
display: none;
}
.suggestions-wrapper {
margin: -0.5rem -0.75rem;
}
.suggestion {
cursor: pointer;
}
.suggestion:nth-child(even) {
background: #f1f1f1;
}
.suggestion-arrow {
display: none;
width: 16px;
}
.suggestion-icon {
width: 16px;
}
.suggestion:hover {
background: #d7d7d7;
}
.suggestion:hover > .suggestion-arrow {
display: initial;
}
.suggestion:hover > .suggestion-icon {
display: none;
}
.search-clear,
.search-clear:focus,
.search-clear:hover,
.search-clear:active {
position: relative;
left: -35px;
margin-right: -35px;
border: none;
}
</style>
......@@ -5,7 +5,7 @@
<!-- Brand and toggle get grouped for better mobile display -->
<b-navbar-brand to="/">
<img class="d-inline-block align-top scc-img" alt="SCC" src="@/assets/img/scc_logo_small.png"/>
<span v-if="!$sysinfo.host_oper_mode.is_prod"> Instanz: {{$sysinfo.host_oper_mode.mode}}</span>
<span v-if="!$sysinfo.host_oper_mode.is_prod"> Instanz: {{ $sysinfo.host_oper_mode.mode }}</span>
</b-navbar-brand>
<b-navbar-toggle target="navbarNavDropdown">
<font-awesome-icon icon="bars"/>
......@@ -27,36 +27,23 @@
</b-nav-item>
</b-navbar-nav>
<b-navbar-nav class="ml-auto">
<b-form inline @submit="searchAction" class="mr-2">
<transition name="slide">
<b-form-input v-if="show_search || ($refs.navdropdown && $refs.navdropdown.show)" ref="search"
size="sm" placeholder="Suche"
v-model="search_input" class="mr-2 search"/>
</transition>
<b-button class="search-button" size="sm" @click="searchAction"
:variant="search_input === '' ? 'secondary' : 'success'">
<font-awesome-icon :icon="['fas','search']"/>
</b-button>
<div class="search-cover-wrapper">
<div class="search-cover"/>
</div>
</b-form>
<GlobalSearch/>
<b-nav-item :active="$store.state.show_sidebar"
@click.stop="$store.commit('showSidebar', !$store.state.show_sidebar)">
<font-awesome-icon :icon="['fas', 'tasks']"/>
Geplante Aktionen
<b-badge variant="primary">{{$store.state.ta_list ? $store.state.ta_list.length : 0}}</b-badge>
<b-badge variant="primary">{{ $store.state.ta_list ? $store.state.ta_list.length : 0 }}</b-badge>
</b-nav-item>
<b-nav-item-dropdown v-if="$store.state.user" right
:toggle-class="$route.path.startsWith('/user/')?'active':''">
<template slot="button-content">
<font-awesome-icon :icon="['fas', 'user']"/>
<span v-if="$store.state.user"> {{$store.state.user.login_name}}</span>
<span v-if="$store.state.user"> {{ $store.state.user.login_name }}</span>
</template>
<template v-if="$store.state.user">
<b-dropdown-item to="/user/tokens" :active="$route.path === '/user/tokens'">
<font-awesome-icon :icon="['fas', 'code']"/>
API-Tokens
Accounts & Tokens
</b-dropdown-item>
<b-dropdown-divider/>
<b-dropdown-item @click="logout">
......@@ -75,79 +62,25 @@
</template>
<script>
import LoginService from '@/api-services/login.service'
import LoginService from '@/api-services/login.service'
import GlobalSearch from "@/components/GlobalSearch";
export default {
export default {
name: "Navbar",
components: {GlobalSearch},
data() {
return {
show_search: false,
search_input: ''
}
return {}
},
methods: {
async logout() {
if(this.$store.token == null) {
if (this.$store.token == null) {
await LoginService.logout(null)
}
else {
} else {
await LoginService.logout(this.$store.state.token.pk || null)
}
this.$store.commit('logout')
await this.$router.push('/login')
},
searchAction(e) {
e.preventDefault()
if (this.search_input === '') {
this.show_search = !this.show_search
if (this.show_search) {
this.$nextTick(() => {
this.$refs.search.focus()
})
}
} else {
// TODO: actually search stuff
window.console.log('Search: ' + this.search_input)
this.search_input = ''
}
}
}
}
}
</script>
\ No newline at end of file
<style scoped>
.slide-enter-active,
.slide-leave-active {
transition: transform 250ms;
z-index: -10;
}
.slide-enter,
.slide-leave-to {
transform: translateX(120%);
}
.search-cover-wrapper {
position: relative;
width: 0;
height: 0;
}
.search-cover {
z-index: -1;
position: absolute;
left: -30px;
top: -25px;
width: 300px;
height: 50px;
background: #343A40;
}
.search {
max-width: 250px;
}
.search-button {
z-index: 1;
}
</style>
......@@ -33,6 +33,9 @@ import {
faSignOutAlt,
faUser,
faEye,
faLink,
faQuestion,
faTimes
} from '@fortawesome/free-solid-svg-icons'
import {
......@@ -81,4 +84,7 @@ library.add(
faPaperPlane,
faOpenid,
faEye,
faLink,
faQuestion,
faTimes
)
......@@ -46,7 +46,7 @@ export default new Router({
component: () => import('./views/netdb/Tokens.vue'),
meta: {
resolveName: function () {
return "API-Tokens"
return "Accounts & Tokens"
}
}
},
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment