Files
raven-client/ayanova/src/views/home-search.vue
2020-05-13 23:22:13 +00:00

402 lines
11 KiB
Vue

<template>
<v-row v-if="formState.ready">
<v-col>
<v-form ref="form">
<v-row justify="start">
<gz-error :errorBoxMessage="formState.errorBoxMessage"></gz-error>
<v-col cols="12" sm="4" lg="4" xl="3">
<v-text-field
v-model="searchPhrase"
clearable
:label="$ay.t('Search')"
ref="searchPhrase"
@change="getDataFromApi()"
hint="text, *xt, te*"
:data-cy="!!$ay.dev ? 'phrase' : false"
></v-text-field>
</v-col>
<v-col cols="12" sm="4" lg="4" xl="3">
<v-select
v-model="searchObjectType"
:items="selectLists.objectTypes"
item-text="name"
item-value="id"
:label="$ay.t('Object')"
></v-select>
</v-col>
<v-col cols="12" sm="4" lg="4" xl="3">
<v-btn color="primary" v-on:click="getDataFromApi()" value="SEARCH">
<v-icon :data-cy="!!$ay.dev ? 'btnsearch' : false"
>fa-search</v-icon
>
</v-btn>
</v-col>
<v-col cols="12">
<p v-if="!items.length">{{ $ay.t("NoResults") }}</p>
<v-card v-if="items.length" max-width="900">
<v-list>
<v-subheader v-if="maxResultsReturned">
<span>({{ $ay.t("TooManyResults") }})</span>
</v-subheader>
<template v-for="item in items">
<!-- KEY MUST BE UNIQUE INSIDE v-for OR LIST ITEM GOES SNAKEY -->
<v-subheader :key="'s' + item.index" v-if="item.subheader"
><v-icon large class="mr-2">{{ item.icon }}</v-icon
><span class="title">{{
item.subheader
}}</span></v-subheader
>
<v-list-item link :key="item.index">
<v-list-item-content
@click="openItem(item)"
:data-cy="!!$ay.dev ? 'btnopenitem' + item.index : false"
>
<v-list-item-title v-text="item.name"></v-list-item-title>
<v-list-item-subtitle
v-html="item.info"
></v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-btn icon @click="getExcerpt(item)">
<v-icon
color="grey lighten-1"
large
:data-cy="
!!$ay.dev ? 'btnexcerpt' + item.index : false
"
>fa-info-circle</v-icon
>
</v-btn>
</v-list-item-action>
</v-list-item>
</template>
</v-list>
</v-card>
</v-col>
</v-row>
</v-form>
</v-col>
</v-row>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Xeslint-disable */
////////////////////////////////////////////////////////////////////////////////////////////////////////////
const FORM_KEY = "home-search";
const API_BASE_URL = "search/";
const FORM_CUSTOM_TEMPLATE_KEY = "home-search";
const MAX_RESULTS = 200;
export default {
beforeRouteLeave(to, from, next) {
let vm = this;
//save last search in session cache
window.$gz.form.setFormSettings(FORM_KEY, {
temp: {
ayaType: vm.searchObjectType,
phrase: vm.searchPhrase,
items: vm.items,
maxResultsReturned: vm.maxResultsReturned
}
});
next();
},
created() {
let vm = this;
initForm(vm)
.then(() => {
vm.formState.ready = true;
window.$gz.eventBus.$on("menu-click", clickHandler);
generateMenu(vm);
if (vm.$route.params.ayatype) {
vm.searchObjectType = vm.$route.params.ayatype;
}
//get form settings from session cache, if same type as in route then re-use teh last search stuff
//however if different than need to clear it (or not rehydrate it)
let savedSettings = window.$gz.form.getFormSettings(FORM_KEY);
if (savedSettings && savedSettings.temp) {
savedSettings = savedSettings.temp;
if (
vm.searchObjectType == null ||
vm.searchObjectType == savedSettings.ayaType
) {
//same type or no type so go ahead and rehydrate
vm.searchPhrase = savedSettings.phrase;
vm.searchObjectType = savedSettings.ayaType;
vm.items = savedSettings.items;
}
}
})
.catch(err => {
vm.formState.ready = true;
window.$gz.errorHandler.handleFormError(err, vm);
});
},
beforeDestroy() {
window.$gz.eventBus.$off("menu-click", clickHandler);
},
components: {},
data() {
return {
formCustomTemplateKey: FORM_CUSTOM_TEMPLATE_KEY,
selectLists: {
objectTypes: []
},
searchPhrase: null,
searchObjectType: 0,
items: [],
maxResultsReturned: false,
formState: {
ready: false,
dirty: false,
valid: true,
readOnly: false,
loading: false,
errorBoxMessage: null,
appError: null,
serverError: {}
},
rights: window.$gz.role.defaultRightsObject()
};
},
methods: {
openItem(item) {
window.$gz.eventBus.$emit("openobject", {
type: item.type,
id: item.id
});
},
getExcerpt(item) {
let vm = this;
//Search/Info/2/1?phrase=we
if (item.info || item.id == 0) {
return;
}
let max = 40;
switch (vm.$vuetify.breakpoint.name) {
case "xs":
max = 30;
break;
case "sm":
max = 67;
break;
case "md":
max = 78;
break;
case "lg":
max = 120;
break;
case "xl":
max = 120;
break;
default:
max = 40;
}
window.$gz.api
.get(
API_BASE_URL +
"Info/" +
item.type +
"/" +
item.id +
"?phrase=" +
vm.searchPhrase +
"&max=" +
max
)
.then(res => {
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//Aya<span class="v-list-item__mask">Nov</span>
// <v-list-item-subtitle v-html="item.subtitle"></v-list-item-subtitle>
//subtitle: "<span class='text--primary'>to Alex, Scott, Jennifer</span> &mdash; Wish I could come, but I'm out of town this weekend.",
let showInfo = res.data;
let searchTerms = vm.searchPhrase
.toLocaleLowerCase()
.replace(/[*]/gi, "")
.split(" ");
for (let i = 0; i < searchTerms.length; i++) {
showInfo = showInfo.replace(
searchTerms[i],
"<span class='v-list-item__mask'>" + searchTerms[i] + "</span>"
);
}
item.info = showInfo;
}
})
.catch(function handleGetDataFromAPIError(error) {
window.$gz.errorHandler.handleFormError(error, vm);
});
},
getDataFromApi() {
let vm = this;
if (!vm.searchPhrase || vm.formState.loading) {
return;
}
vm.formState.loading = true;
window.$gz.form.deleteAllErrorBoxErrors(vm);
/**
* {
"phrase": "e*",
"nameOnly": false,
"typeOnly": 0,
"maxResults": 100
}
*
*/
window.$gz.api
.upsert(API_BASE_URL, {
phrase: vm.searchPhrase,
nameOnly: false,
typeOnly: !!vm.searchObjectType ? vm.searchObjectType : 0,
maxResults: MAX_RESULTS
})
.then(res => {
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
vm.maxResultsReturned =
res.data.searchResults.length == MAX_RESULTS;
let newResults = [];
let nDex = 0;
let lastType = -1;
for (let i = 0; i < res.data.searchResults.length; i++) {
let item = res.data.searchResults[i];
if (item.type != lastType) {
//change of type, set subheader props
let tsub = window.$gz._.find(vm.selectLists.objectTypes, [
"id",
item.type
]);
if (tsub != null) {
item.subheader = tsub.name;
} else {
item.subheader = "TYPE " + item.type;
}
item.icon = window.$gz.util.iconForType(item.type);
lastType = item.type;
}
item.info = null;
item.index = ++nDex;
newResults.push(item);
}
vm.items = newResults;
}
})
.catch(function handleGetDataFromAPIError(error) {
window.$gz.errorHandler.handleFormError(error, vm);
})
.finally(function() {
//Update the form status
window.$gz.form.setFormState({
vm: vm,
loading: false
});
});
}
}
};
/////////////////////////////
//
//
function clickHandler(menuItem) {
if (!menuItem) {
return;
}
let m = window.$gz.menu.parseMenuItem(menuItem);
if (m.owner == FORM_KEY && !m.disabled) {
switch (m.key) {
default:
window.$gz.eventBus.$emit(
"notify-warning",
FORM_KEY + "::context click: [" + m.key + "]"
);
}
}
}
//////////////////////
//
//
function generateMenu(vm) {
let menuOptions = {
isMain: true,
icon: "fa-search",
title: vm.$ay.t("Search"),
helpUrl: "form-home-search",
formData: {
ayaType: window.$gz.type.UserOptions
},
menuItems: []
};
window.$gz.eventBus.$emit("menu-change", menuOptions);
}
/////////////////////////////////
//
//
function initForm(vm) {
return new Promise(function(resolve, reject) {
(async function() {
try {
await fetchTranslatedText(vm);
await populateSelectionLists(vm);
} catch (err) {
reject(err);
}
resolve();
})();
});
}
//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
function fetchTranslatedText(vm) {
return window.$gz.translation.fetch([
"TooManyResults",
"NoResults",
"Object"
]);
}
//////////////////////
//
//
function populateSelectionLists(vm) {
return window.$gz.api.get("enum-list/list/Core").then(res => {
if (res.error) {
window.$gz.errorHandler.handleFormError(res.error, vm);
} else {
vm.selectLists.objectTypes = res.data;
window.$gz.form.addNoSelectionItem(vm.selectLists.objectTypes);
}
});
}
</script>