Skip to content

Commit

Permalink
first steps to advanced search
Browse files Browse the repository at this point in the history
  • Loading branch information
vabene1111 committed Jan 3, 2025
1 parent dc58b42 commit b8db54d
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 46 deletions.
11 changes: 9 additions & 2 deletions vue3/src/components/display/HorizontalRecipeWindow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ import {ApiApi, ApiRecipeListRequest, Keyword, Recipe, RecipeOverview} from "@/o
import {homePageCols} from "@/utils/breakpoint_utils";
import {useI18n} from "vue-i18n";
import {DateTime} from "luxon";
import {tr} from "vuetify/locale";
//TODO mode ideas "last year/month/cooked long ago"
const props = defineProps(
{
mode: {type: String as PropType<'recent' | 'new' | 'keyword' | 'rating'>, required: true},
mode: {type: String as PropType<'recent' | 'new' | 'keyword' | 'rating' | 'random'>, required: true},
skeletons: {type: Number, default: 0},
}
)
Expand All @@ -68,6 +69,8 @@ const title = computed(() => {
switch (props.mode) {
case 'recent':
return t('Recently_Viewed')
case 'random':
return t('Random Recipes')
case 'new':
return t('New')
case 'rating':
Expand All @@ -87,6 +90,8 @@ const icon = computed(() => {
switch (props.mode) {
case 'recent':
return 'fa-solid fa-eye'
case 'random':
return 'fa-solid fa-dice'
case 'new':
return 'fa-solid fa-calendar-alt'
case 'rating':
Expand Down Expand Up @@ -116,9 +121,11 @@ function loadRecipes() {
switch (props.mode) {
case 'recent':
// TODO implement correct parameter
requestParameters.numRecent = 16
break;
case 'random':
requestParameters.random = 'true'
break;
case 'new':
requestParameters._new = 'true'
break;
Expand Down
22 changes: 14 additions & 8 deletions vue3/src/components/inputs/GlobalSearchDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,20 @@ const searchResults = computed(() => {
let searchResults = [] as Array<SearchResult>
if (searchQuery.value != '' && searchQuery.value != null) {
// TODO add link to advanced search once it exists
//searchResults.push({name: searchQuery.value, icon: 'fas fa-search', suffix: 'Advanced Search'} as SearchResult)
flatRecipes.value.filter(fr => fr.name.toLowerCase().includes(searchQuery.value.toLowerCase())).slice(0, 10).forEach(r => {
searchResults.push({name: r.name, image: r.image, recipeId: r.id} as SearchResult)
searchResults.push({name: r.name, image: r.image, recipeId: r.id, type: "recipe"} as SearchResult)
})
if (searchResults.length < 3) {
asyncSearchResults.value.slice(0, 5).forEach(r => {
if (searchResults.findIndex(x => x.recipeId == r.id) == -1) {
searchResults.push({name: r.name, image: r.image, recipeId: r.id})
searchResults.push({name: r.name, image: r.image, recipeId: r.id, type: "recipe"})
}
})
}
searchResults.push({name: searchQuery.value, icon: 'fas fa-search', type: "link_advanced_search"} as SearchResult)
} else {
// show first 5 recipes by default
Expand Down Expand Up @@ -212,10 +211,17 @@ function cardVariant(index: number) {
function goToSelectedRecipe(index: number) {
dialog.value = false
let searchResult = searchResults.value[index]
console.log('going to', searchResult.recipeId)
if (searchResult.recipeId != null) {
router.push({name: 'view_recipe', params: {'id': searchResult.recipeId}})
if (searchResult.type == 'link_advanced_search') {
router.push({name: 'view_search', query: {'query': searchQuery.value}})
} else {
console.log('going to', searchResult.recipeId)
if (searchResult.recipeId != null) {
router.push({name: 'view_recipe', params: {'id': searchResult.recipeId}})
}
}
}
</script>

Expand Down
3 changes: 2 additions & 1 deletion vue3/src/components/inputs/ModelSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
:on-create="createObject"
:createOption="props.allowCreate"
:delay="300"
:object="true"
:object="props.object"
:valueProp="itemValue"
:label="itemLabel"
:searchable="true"
Expand Down Expand Up @@ -72,6 +72,7 @@ const props = defineProps({
mode: {type: String as PropType<'single' | 'multiple' | 'tags'>, default: 'single'},
appendToBody: {type: Boolean, default: false},
object: {type: Boolean, default: true},
allowCreate: {type: Boolean, default: false},
Expand Down
46 changes: 46 additions & 0 deletions vue3/src/components/model_editors/CustomFilterEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<template>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form :disabled="loading">
Coming Soon
</v-form>
</v-card-text>
</model-editor-base>
</template>

<script setup lang="ts">
import {onMounted, PropType} from "vue";
import {CustomFilter} from "@/openapi";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
const props = defineProps({
item: {type: {} as PropType<CustomFilter>, required: false, default: null},
itemId: {type: [Number, String], required: false, default: undefined},
dialog: {type: Boolean, default: false}
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<CustomFilter>('CustomFilter', emit)
onMounted(() => {
setupState(props.item, props.itemId, {})
})
</script>

<style scoped>
</style>
1 change: 0 additions & 1 deletion vue3/src/pages/IngredientEditorPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ const selectedFood = ref<null | Food>(null)
const selectedUnit = ref<null | Unit>(null)
const deleteConfirmDialog = ref(false)
const deleteConfirmIngredient = ref({} as EditorIngredient)
onMounted(() => {
getAndLoadParameters()
Expand Down
158 changes: 126 additions & 32 deletions vue3/src/pages/SearchPage.vue
Original file line number Diff line number Diff line change
@@ -1,43 +1,137 @@
<template>

<v-container>
<v-btn @click="testApi">Test API</v-btn>
</v-container>
<v-row>
<v-col>
<v-card :loading="loading">
<v-card-title>
{{ $t('Search') }}
</v-card-title>
<v-card-text>
<v-form :disabled="loading">
<v-text-field :label="$t('Search')" v-model="searchParameters.query" clearable></v-text-field>

<model-select model="Keyword" mode="tags" v-model="searchParameters.keywords" :object="false"></model-select>
<model-select model="Food" mode="tags" v-model="searchParameters.foods"></model-select>
<model-select model="Unit" mode="tags" v-model="searchParameters.units"></model-select>
<model-select model="RecipeBook" mode="tags" v-model="searchParameters.books"></model-select>

<!-- <v-number-input :label="$t('times_cooked')" v-model="searchParameters.timescooked" clearable></v-number-input>-->
<!-- <v-date-input :label="$t('last_cooked')" v-model="searchParameters.cookedon" clearable></v-date-input>-->
<!-- <v-date-input :label="$t('last_viewed')" v-model="searchParameters.viewedon" clearable></v-date-input>-->
<!-- <v-date-input :label="$t('created_on')" v-model="searchParameters.createdon" clearable></v-date-input>-->
<!-- <v-date-input :label="$t('updatedon')" v-model="searchParameters.updatedon" clearable></v-date-input>-->

<v-checkbox :label="$t('make_now')" v-model="searchParameters.makenow"></v-checkbox>
</v-form>


</v-card-text>
<v-card-actions>
<v-btn @click="reset()">{{ $t('Reset') }}</v-btn>
<v-btn @click="searchRecipes()">{{ $t('Search') }}</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>

<v-row v-if="recipes.length > 0">
<v-col>
<v-card>
<v-data-table-server
:loading="loading"
:items="recipes"
:headers="tableHeaders"
:page="searchParameters.page"
:items-per-page="searchParameters.pageSize"
:items-length="tableItemCount"
@click:row="handleRowClick"
>
<template #item.image="{item}">
<v-avatar :image="item.image"></v-avatar>
</template>

<template #item.keywords="{item}">
<keywords-bar :keywords="item.keywords"></keywords-bar>
</template>

<template #item.action="{item}">
<recipe-context-menu :recipe="item"></recipe-context-menu>
</template>
</v-data-table-server>
</v-card>
</v-col>
</v-row>
</v-container>
</template>

<script lang="ts">
import {defineComponent} from 'vue'
<script setup lang="ts">
import {onMounted, ref, watch} from "vue";
import {ApiApi, ApiRecipeListRequest, RecipeOverview} from "@/openapi";
import {useUrlSearchParams} from "@vueuse/core";
import {useI18n} from "vue-i18n";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
import RecipeCard from "@/components/display/RecipeCard.vue";
import {ApiApi, Recipe, RecipeOverview} from "@/openapi";
export default defineComponent({
name: "SearchPage",
components: {ModelSelect, RecipeCard},
data() {
return {
test: {
text: String,
},
}
},
mounted() {
},
methods: {
testApi: function () {
const api = new ApiApi()
api.apiMealPlanList().then(r => {
if (r.length > 0 && r[0].id != undefined) {
api.apiMealPlanUpdate({id: r[0].id, mealPlanRequest: r[0]})
}
})
}
}
import {VNumberInput} from 'vuetify/labs/VNumberInput'
import {VDateInput} from 'vuetify/labs/VDateInput'
import RecipeContextMenu from "@/components/inputs/RecipeContextMenu.vue";
import {useRouter} from "vue-router";
import KeywordsBar from "@/components/display/KeywordsBar.vue";
const {t} = useI18n()
const router = useRouter()
const urlSearchParams = useUrlSearchParams('history', {})
const searchParameters = ref({} as ApiRecipeListRequest)
const loading = ref(false)
const tableHeaders = [
{title: t('Image'), width: '1%', noBreak: true, key: 'image',},
{title: t('Name'), key: 'name',},
{title: t('Keywords'), key: 'keywords',},
{title: t('Actions'), key: 'action', width: '1%', noBreak: true, align: 'end'},
]
const tableItemCount = ref(0)
const recipes = ref([] as RecipeOverview[])
watch(() => searchParameters.value.page, () => {
searchRecipes()
})
watch(() => searchParameters.value.pageSize, () => {
searchRecipes()
})
onMounted(() => {
if (urlSearchParams.query && typeof urlSearchParams.query === "string") {
searchParameters.value.query = urlSearchParams.query
}
})
function searchRecipes() {
let api = new ApiApi()
loading.value = true
api.apiRecipeList(searchParameters.value).then((r) => {
recipes.value = r.results
tableItemCount.value = r.count
}).catch(err => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
}).finally(() => {
loading.value = false
})
}
function reset() {
searchParameters.value = {} as ApiRecipeListRequest
recipes.value = []
}
function handleRowClick(event: PointerEvent, data: any) {
router.push({name: 'view_recipe', params: {id: recipes.value[data.index].id}})
}
</script>

<style scoped>
Expand Down
1 change: 1 addition & 0 deletions vue3/src/pages/StartPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<horizontal-recipe-scroller :skeletons="4" mode="recent"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="4" mode="new"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="4" mode="keyword"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="4" mode="random"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="2" mode="rating"></horizontal-recipe-scroller>
<horizontal-recipe-scroller :skeletons="4" mode="keyword"></horizontal-recipe-scroller>

Expand Down
Loading

0 comments on commit b8db54d

Please sign in to comment.