mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-30 17:53:31 -04:00 
			
		
		
		
	fix: QueryFilter Hydration & script setup (#5839)
This commit is contained in:
		| @@ -44,33 +44,17 @@ | |||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script lang="ts"> | <script setup lang="ts"> | ||||||
| import type { ReadCookBook } from "~/lib/api/types/cookbook"; |  | ||||||
| import { Organizer } from "~/lib/api/types/non-generated"; | import { Organizer } from "~/lib/api/types/non-generated"; | ||||||
| import QueryFilterBuilder from "~/components/Domain/QueryFilterBuilder.vue"; | import QueryFilterBuilder from "~/components/Domain/QueryFilterBuilder.vue"; | ||||||
| import type { FieldDefinition } from "~/composables/use-query-filter-builder"; | import type { FieldDefinition } from "~/composables/use-query-filter-builder"; | ||||||
|  | import type { ReadCookBook } from "~/lib/api/types/cookbook"; | ||||||
|  |  | ||||||
| export default defineNuxtComponent({ | const modelValue = defineModel<ReadCookBook>({ required: true }); | ||||||
|   components: { QueryFilterBuilder }, |  | ||||||
|   props: { |  | ||||||
|     modelValue: { |  | ||||||
|       type: Object as () => ReadCookBook, |  | ||||||
|       required: true, |  | ||||||
|     }, |  | ||||||
|     actions: { |  | ||||||
|       type: Object as () => any, |  | ||||||
|       required: true, |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
|   emits: ["update:modelValue"], |  | ||||||
|   setup(props, { emit }) { |  | ||||||
| const i18n = useI18n(); | const i18n = useI18n(); | ||||||
|  | const cookbook = toRef(modelValue); | ||||||
|     const cookbook = toRef(() => props.modelValue); |  | ||||||
|  |  | ||||||
| function handleInput(value: string | undefined) { | function handleInput(value: string | undefined) { | ||||||
|   cookbook.value.queryFilterString = value || ""; |   cookbook.value.queryFilterString = value || ""; | ||||||
|       emit("update:modelValue", cookbook.value); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| const fieldDefs: FieldDefinition[] = [ | const fieldDefs: FieldDefinition[] = [ | ||||||
| @@ -110,12 +94,4 @@ export default defineNuxtComponent({ | |||||||
|     type: "date", |     type: "date", | ||||||
|   }, |   }, | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
|     return { |  | ||||||
|       cookbook, |  | ||||||
|       handleInput, |  | ||||||
|       fieldDefs, |  | ||||||
|     }; |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -17,7 +17,6 @@ | |||||||
|       <v-card-text> |       <v-card-text> | ||||||
|         <CookbookEditor |         <CookbookEditor | ||||||
|           v-model="editTarget" |           v-model="editTarget" | ||||||
|           :actions="actions" |  | ||||||
|         /> |         /> | ||||||
|       </v-card-text> |       </v-card-text> | ||||||
|     </BaseDialog> |     </BaseDialog> | ||||||
| @@ -65,7 +64,7 @@ | |||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script lang="ts"> | <script setup lang="ts"> | ||||||
| import { useLazyRecipes } from "~/composables/recipes"; | import { useLazyRecipes } from "~/composables/recipes"; | ||||||
| import RecipeCardSection from "@/components/Domain/Recipe/RecipeCardSection.vue"; | import RecipeCardSection from "@/components/Domain/Recipe/RecipeCardSection.vue"; | ||||||
| import { useCookbookStore } from "~/composables/store/use-cookbook-store"; | import { useCookbookStore } from "~/composables/store/use-cookbook-store"; | ||||||
| @@ -74,9 +73,6 @@ import { useLoggedInState } from "~/composables/use-logged-in-state"; | |||||||
| import type { RecipeCookBook } from "~/lib/api/types/cookbook"; | import type { RecipeCookBook } from "~/lib/api/types/cookbook"; | ||||||
| import CookbookEditor from "~/components/Domain/Cookbook/CookbookEditor.vue"; | import CookbookEditor from "~/components/Domain/Cookbook/CookbookEditor.vue"; | ||||||
|  |  | ||||||
| export default defineNuxtComponent({ |  | ||||||
|   components: { RecipeCardSection, CookbookEditor }, |  | ||||||
|   setup() { |  | ||||||
| const $auth = useMealieAuth(); | const $auth = useMealieAuth(); | ||||||
| const { isOwnGroup } = useLoggedInState(); | const { isOwnGroup } = useLoggedInState(); | ||||||
|  |  | ||||||
| @@ -89,7 +85,6 @@ export default defineNuxtComponent({ | |||||||
| const { actions } = useCookbookStore(); | const { actions } = useCookbookStore(); | ||||||
| const router = useRouter(); | const router = useRouter(); | ||||||
|  |  | ||||||
|     const tab = ref(null); |  | ||||||
| const book = getOne(slug); | const book = getOne(slug); | ||||||
|  |  | ||||||
| const isOwnHousehold = computed(() => { | const isOwnHousehold = computed(() => { | ||||||
| @@ -132,23 +127,4 @@ export default defineNuxtComponent({ | |||||||
| useSeoMeta({ | useSeoMeta({ | ||||||
|   title: book?.value?.name || "Cookbook", |   title: book?.value?.name || "Cookbook", | ||||||
| }); | }); | ||||||
|  |  | ||||||
|     return { |  | ||||||
|       book, |  | ||||||
|       slug, |  | ||||||
|       tab, |  | ||||||
|       appendRecipes, |  | ||||||
|       assignSorted, |  | ||||||
|       recipes, |  | ||||||
|       removeRecipe, |  | ||||||
|       replaceRecipes, |  | ||||||
|       canEdit, |  | ||||||
|       dialogStates, |  | ||||||
|       editTarget, |  | ||||||
|       handleEditCookbook, |  | ||||||
|       editCookbook, |  | ||||||
|       actions, |  | ||||||
|     }; |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -163,14 +163,14 @@ | |||||||
|                 max-width="290px" |                 max-width="290px" | ||||||
|                 min-width="auto" |                 min-width="auto" | ||||||
|               > |               > | ||||||
|                 <template #activator="{ props }"> |                 <template #activator="{ props: activatorProps }"> | ||||||
|                   <v-text-field |                   <v-text-field | ||||||
|                     v-model="field.value" |                     v-model="field.value" | ||||||
|                     persistent-hint |                     persistent-hint | ||||||
|                     :prepend-icon="$globals.icons.calendar" |                     :prepend-icon="$globals.icons.calendar" | ||||||
|                     variant="underlined" |                     variant="underlined" | ||||||
|                     color="primary" |                     color="primary" | ||||||
|                     v-bind="props" |                     v-bind="activatorProps" | ||||||
|                     readonly |                     readonly | ||||||
|                   /> |                   /> | ||||||
|                 </template> |                 </template> | ||||||
| @@ -184,53 +184,48 @@ | |||||||
|               </v-menu> |               </v-menu> | ||||||
|               <RecipeOrganizerSelector |               <RecipeOrganizerSelector | ||||||
|                 v-else-if="field.type === Organizer.Category" |                 v-else-if="field.type === Organizer.Category" | ||||||
|                 :model-value="field.organizers" |                 v-model="field.organizers" | ||||||
|                 :selector-type="Organizer.Category" |                 :selector-type="Organizer.Category" | ||||||
|                 :show-add="false" |                 :show-add="false" | ||||||
|                 :show-label="false" |                 :show-label="false" | ||||||
|                 :show-icon="false" |                 :show-icon="false" | ||||||
|                 variant="underlined" |                 variant="underlined" | ||||||
|                 @update:model-value="setOrganizerValues(field, index, $event)" |  | ||||||
|               /> |               /> | ||||||
|               <RecipeOrganizerSelector |               <RecipeOrganizerSelector | ||||||
|                 v-else-if="field.type === Organizer.Tag" |                 v-else-if="field.type === Organizer.Tag" | ||||||
|                 :model-value="field.organizers" |                 v-model="field.organizers" | ||||||
|                 :selector-type="Organizer.Tag" |                 :selector-type="Organizer.Tag" | ||||||
|                 :show-add="false" |                 :show-add="false" | ||||||
|                 :show-label="false" |                 :show-label="false" | ||||||
|                 :show-icon="false" |                 :show-icon="false" | ||||||
|                 variant="underlined" |                 variant="underlined" | ||||||
|                 @update:model-value="setOrganizerValues(field, index, $event)" |  | ||||||
|               /> |               /> | ||||||
|               <RecipeOrganizerSelector |               <RecipeOrganizerSelector | ||||||
|                 v-else-if="field.type === Organizer.Tool" |                 v-else-if="field.type === Organizer.Tool" | ||||||
|                 :model-value="field.organizers" |                 v-model="field.organizers" | ||||||
|                 :selector-type="Organizer.Tool" |                 :selector-type="Organizer.Tool" | ||||||
|                 :show-add="false" |                 :show-add="false" | ||||||
|                 :show-label="false" |                 :show-label="false" | ||||||
|                 :show-icon="false" |                 :show-icon="false" | ||||||
|                 variant="underlined" |                 variant="underlined" | ||||||
|                 @update:model-value="setOrganizerValues(field, index, $event)" |  | ||||||
|               /> |               /> | ||||||
|               <RecipeOrganizerSelector |               <RecipeOrganizerSelector | ||||||
|                 v-else-if="field.type === Organizer.Food" |                 v-else-if="field.type === Organizer.Food" | ||||||
|                 :model-value="field.organizers" |                 v-model="field.organizers" | ||||||
|                 :selector-type="Organizer.Food" |                 :selector-type="Organizer.Food" | ||||||
|                 :show-add="false" |                 :show-add="false" | ||||||
|                 :show-label="false" |                 :show-label="false" | ||||||
|                 :show-icon="false" |                 :show-icon="false" | ||||||
|                 variant="underlined" |                 variant="underlined" | ||||||
|                 @update:model-value="setOrganizerValues(field, index, $event)" |  | ||||||
|               /> |               /> | ||||||
|               <RecipeOrganizerSelector |               <RecipeOrganizerSelector | ||||||
|                 v-else-if="field.type === Organizer.Household" |                 v-else-if="field.type === Organizer.Household" | ||||||
|                 :model-value="field.organizers" |                 v-model="field.organizers" | ||||||
|                 :selector-type="Organizer.Household" |                 :selector-type="Organizer.Household" | ||||||
|                 :show-add="false" |                 :show-add="false" | ||||||
|                 :show-label="false" |                 :show-label="false" | ||||||
|                 :show-icon="false" |                 :show-icon="false" | ||||||
|                 variant="underlined" |                 variant="underlined" | ||||||
|                 @update:model-value="setOrganizerValues(field, index, $event)" |  | ||||||
|               /> |               /> | ||||||
|             </v-col> |             </v-col> | ||||||
|             <!-- right parenthesis --> |             <!-- right parenthesis --> | ||||||
| @@ -297,7 +292,7 @@ | |||||||
|   </v-card> |   </v-card> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script lang="ts"> | <script setup lang="ts"> | ||||||
| import { VueDraggable } from "vue-draggable-plus"; | import { VueDraggable } from "vue-draggable-plus"; | ||||||
| import { useDebounceFn } from "@vueuse/core"; | import { useDebounceFn } from "@vueuse/core"; | ||||||
| import { useHouseholdSelf } from "~/composables/use-households"; | import { useHouseholdSelf } from "~/composables/use-households"; | ||||||
| @@ -307,12 +302,7 @@ import type { LogicalOperator, QueryFilterJSON, QueryFilterJSONPart, RelationalK | |||||||
| import { useCategoryStore, useFoodStore, useHouseholdStore, useTagStore, useToolStore } from "~/composables/store"; | import { useCategoryStore, useFoodStore, useHouseholdStore, useTagStore, useToolStore } from "~/composables/store"; | ||||||
| import { type Field, type FieldDefinition, type FieldValue, type OrganizerBase, useQueryFilterBuilder } from "~/composables/use-query-filter-builder"; | import { type Field, type FieldDefinition, type FieldValue, type OrganizerBase, useQueryFilterBuilder } from "~/composables/use-query-filter-builder"; | ||||||
|  |  | ||||||
| export default defineNuxtComponent({ | const props = defineProps({ | ||||||
|   components: { |  | ||||||
|     VueDraggable, |  | ||||||
|     RecipeOrganizerSelector, |  | ||||||
|   }, |  | ||||||
|   props: { |  | ||||||
|   fieldDefs: { |   fieldDefs: { | ||||||
|     type: Array as () => FieldDefinition[], |     type: Array as () => FieldDefinition[], | ||||||
|     required: true, |     required: true, | ||||||
| @@ -321,9 +311,13 @@ export default defineNuxtComponent({ | |||||||
|     type: Object as () => QueryFilterJSON | null, |     type: Object as () => QueryFilterJSON | null, | ||||||
|     default: null, |     default: null, | ||||||
|   }, |   }, | ||||||
|   }, | }); | ||||||
|   emits: ["input", "inputJSON"], |  | ||||||
|   setup(props, context) { | const emit = defineEmits<{ | ||||||
|  |   (event: "input", value: string | undefined): void; | ||||||
|  |   (event: "inputJSON", value: QueryFilterJSON | undefined): void; | ||||||
|  | }>(); | ||||||
|  |  | ||||||
| const { household } = useHouseholdSelf(); | const { household } = useHouseholdSelf(); | ||||||
| const { logOps, relOps, buildQueryFilterString, getFieldFromFieldDef, isOrganizerType } = useQueryFilterBuilder(); | const { logOps, relOps, buildQueryFilterString, getFieldFromFieldDef, isOrganizerType } = useQueryFilterBuilder(); | ||||||
|  |  | ||||||
| @@ -337,6 +331,7 @@ export default defineNuxtComponent({ | |||||||
|   datePickers: [] as boolean[], |   datePickers: [] as boolean[], | ||||||
|   drag: false, |   drag: false, | ||||||
| }); | }); | ||||||
|  | const { showAdvanced, datePickers, drag } = toRefs(state); | ||||||
|  |  | ||||||
| const storeMap = { | const storeMap = { | ||||||
|   [Organizer.Category]: useCategoryStore(), |   [Organizer.Category]: useCategoryStore(), | ||||||
| @@ -369,7 +364,7 @@ export default defineNuxtComponent({ | |||||||
|     id: useUid(), |     id: useUid(), | ||||||
|   }); |   }); | ||||||
|   state.datePickers.push(false); |   state.datePickers.push(false); | ||||||
| 		}; | } | ||||||
|  |  | ||||||
| function setField(index: number, fieldLabel: string) { | function setField(index: number, fieldLabel: string) { | ||||||
|   state.datePickers[index] = false; |   state.datePickers[index] = false; | ||||||
| @@ -419,15 +414,10 @@ export default defineNuxtComponent({ | |||||||
|   fields.value[index].values = values; |   fields.value[index].values = values; | ||||||
| } | } | ||||||
|  |  | ||||||
| 		function setOrganizerValues(field: FieldWithId, index: number, values: OrganizerBase[]) { |  | ||||||
| 		  setFieldValues(field, index, values.map(value => value.id.toString())); |  | ||||||
| 		  fields.value[index].organizers = values; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| function removeField(index: number) { | function removeField(index: number) { | ||||||
|   fields.value.splice(index, 1); |   fields.value.splice(index, 1); | ||||||
|   state.datePickers.splice(index, 1); |   state.datePickers.splice(index, 1); | ||||||
| 		}; | } | ||||||
|  |  | ||||||
| const fieldsUpdater = useDebounceFn((/* newFields: typeof fields.value */) => { | const fieldsUpdater = useDebounceFn((/* newFields: typeof fields.value */) => { | ||||||
|   /* newFields.forEach((field, index) => { |   /* newFields.forEach((field, index) => { | ||||||
| @@ -441,19 +431,17 @@ export default defineNuxtComponent({ | |||||||
|   } |   } | ||||||
|   state.qfValid = !!qf; |   state.qfValid = !!qf; | ||||||
|  |  | ||||||
| 		  context.emit("input", qf || undefined); |   emit("input", qf || undefined); | ||||||
| 		  context.emit("inputJSON", qf ? buildQueryFilterJSON() : undefined); |   emit("inputJSON", qf ? buildQueryFilterJSON() : undefined); | ||||||
| }, 500); | }, 500); | ||||||
|  |  | ||||||
| watch(fields, fieldsUpdater, { deep: true }); | watch(fields, fieldsUpdater, { deep: true }); | ||||||
|  |  | ||||||
| 		async function hydrateOrganizers(field: FieldWithId, index: number) { | async function hydrateOrganizers(field: FieldWithId, _index: number) { | ||||||
|   if (!field.values?.length || !isOrganizerType(field.type)) { |   if (!field.values?.length || !isOrganizerType(field.type)) { | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| 		  field.organizers = []; |  | ||||||
|  |  | ||||||
|   const { store, actions } = storeMap[field.type]; |   const { store, actions } = storeMap[field.type]; | ||||||
|   if (!store.value.length) { |   if (!store.value.length) { | ||||||
|     await actions.refresh(); |     await actions.refresh(); | ||||||
| @@ -467,8 +455,9 @@ export default defineNuxtComponent({ | |||||||
|     } |     } | ||||||
|     return organizer; |     return organizer; | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   field.organizers = organizers.filter(organizer => organizer !== undefined) as OrganizerBase[]; |   field.organizers = organizers.filter(organizer => organizer !== undefined) as OrganizerBase[]; | ||||||
| 		  setOrganizerValues(field, index, field.organizers); |   return field; | ||||||
| } | } | ||||||
|  |  | ||||||
| function initFieldsError(error = "") { | function initFieldsError(error = "") { | ||||||
| @@ -482,14 +471,15 @@ export default defineNuxtComponent({ | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| 		function initializeFields() { | async function initializeFields() { | ||||||
|   if (!props.initialQueryFilter?.parts?.length) { |   if (!props.initialQueryFilter?.parts?.length) { | ||||||
|     return initFieldsError(); |     return initFieldsError(); | ||||||
| 		  }; |   } | ||||||
|  |  | ||||||
|   const initFields: FieldWithId[] = []; |   const initFields: FieldWithId[] = []; | ||||||
|   let error = false; |   let error = false; | ||||||
| 		  props.initialQueryFilter.parts.forEach((part: QueryFilterJSONPart, index: number) => { |  | ||||||
|  |   for (const [index, part] of props.initialQueryFilter.parts.entries()) { | ||||||
|     const fieldDef = props.fieldDefs.find(fieldDef => fieldDef.name === part.attributeName); |     const fieldDef = props.fieldDefs.find(fieldDef => fieldDef.name === part.attributeName); | ||||||
|     if (!fieldDef) { |     if (!fieldDef) { | ||||||
|       error = true; |       error = true; | ||||||
| @@ -522,7 +512,7 @@ export default defineNuxtComponent({ | |||||||
|       } |       } | ||||||
|  |  | ||||||
|       if (isOrganizerType(field.type)) { |       if (isOrganizerType(field.type)) { | ||||||
| 		        hydrateOrganizers(field, index); |         await hydrateOrganizers(field, index); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     else if (field.type === "boolean") { |     else if (field.type === "boolean") { | ||||||
| @@ -553,7 +543,7 @@ export default defineNuxtComponent({ | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     initFields.push(field); |     initFields.push(field); | ||||||
| 		  }); |   } | ||||||
|  |  | ||||||
|   if (initFields.length && !error) { |   if (initFields.length && !error) { | ||||||
|     fields.value = initFields; |     fields.value = initFields; | ||||||
| @@ -561,14 +551,16 @@ export default defineNuxtComponent({ | |||||||
|   else { |   else { | ||||||
|     initFieldsError(); |     initFieldsError(); | ||||||
|   } |   } | ||||||
| 		}; | } | ||||||
|  |  | ||||||
|  | onMounted(async () => { | ||||||
|   try { |   try { | ||||||
| 		  initializeFields(); |     await initializeFields(); | ||||||
|   } |   } | ||||||
|   catch (error) { |   catch (error) { | ||||||
|     initFieldsError(`Error initializing fields: ${(error || "").toString()}`); |     initFieldsError(`Error initializing fields: ${(error || "").toString()}`); | ||||||
|   } |   } | ||||||
|  | }); | ||||||
|  |  | ||||||
| function buildQueryFilterJSON(): QueryFilterJSON { | function buildQueryFilterJSON(): QueryFilterJSON { | ||||||
|   const parts = fields.value.map((field) => { |   const parts = fields.value.map((field) => { | ||||||
| @@ -643,30 +635,6 @@ export default defineNuxtComponent({ | |||||||
|     }, |     }, | ||||||
|   }; |   }; | ||||||
| }); | }); | ||||||
|  |  | ||||||
| 		return { |  | ||||||
| 		  Organizer, |  | ||||||
| 		  ...toRefs(state), |  | ||||||
| 		  logOps, |  | ||||||
| 		  relOps, |  | ||||||
| 		  config, |  | ||||||
| 		  firstDayOfWeek, |  | ||||||
| 		  onDragEnd, |  | ||||||
| 		  // Fields |  | ||||||
| 		  fields, |  | ||||||
| 		  addField, |  | ||||||
| 		  setField, |  | ||||||
| 		  setLeftParenthesisValue, |  | ||||||
| 		  setRightParenthesisValue, |  | ||||||
| 		  setLogicalOperatorValue, |  | ||||||
| 		  setRelationalOperatorValue, |  | ||||||
| 		  setFieldValue, |  | ||||||
| 		  setFieldValues, |  | ||||||
| 		  setOrganizerValues, |  | ||||||
| 		  removeField, |  | ||||||
| 		}; |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style scoped> | <style scoped> | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
|     v-model="selected" |     v-model="selected" | ||||||
|     v-bind="inputAttrs" |     v-bind="inputAttrs" | ||||||
|     v-model:search="searchInput" |     v-model:search="searchInput" | ||||||
|     :items="storeItem" |     :items="items" | ||||||
|     :label="label" |     :label="label" | ||||||
|     chips |     chips | ||||||
|     closable-chips |     closable-chips | ||||||
| @@ -46,67 +46,40 @@ | |||||||
|   </v-autocomplete> |   </v-autocomplete> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script lang="ts"> | <script setup lang="ts"> | ||||||
| import type { IngredientFood, RecipeCategory, RecipeTag } from "~/lib/api/types/recipe"; | import type { IngredientFood, RecipeCategory, RecipeTag } from "~/lib/api/types/recipe"; | ||||||
| import type { RecipeTool } from "~/lib/api/types/admin"; | import type { RecipeTool } from "~/lib/api/types/admin"; | ||||||
| import { Organizer, type RecipeOrganizer } from "~/lib/api/types/non-generated"; | import { Organizer, type RecipeOrganizer } from "~/lib/api/types/non-generated"; | ||||||
| import type { HouseholdSummary } from "~/lib/api/types/household"; | import type { HouseholdSummary } from "~/lib/api/types/household"; | ||||||
| import { useCategoryStore, useFoodStore, useHouseholdStore, useTagStore, useToolStore } from "~/composables/store"; | import { useCategoryStore, useFoodStore, useHouseholdStore, useTagStore, useToolStore } from "~/composables/store"; | ||||||
|  |  | ||||||
| export default defineNuxtComponent({ | interface Props { | ||||||
|   props: { |   selectorType: RecipeOrganizer; | ||||||
|     modelValue: { |   inputAttrs?: Record<string, any>; | ||||||
|       type: Array as () => ( |   returnObject?: boolean; | ||||||
|  |   showAdd?: boolean; | ||||||
|  |   showLabel?: boolean; | ||||||
|  |   showIcon?: boolean; | ||||||
|  |   variant?: "filled" | "underlined" | "outlined" | "plain" | "solo" | "solo-inverted" | "solo-filled"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const props = withDefaults(defineProps<Props>(), { | ||||||
|  |   inputAttrs: () => ({}), | ||||||
|  |   returnObject: true, | ||||||
|  |   showAdd: true, | ||||||
|  |   showLabel: true, | ||||||
|  |   showIcon: true, | ||||||
|  |   variant: "outlined", | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const selected = defineModel<( | ||||||
|   | HouseholdSummary |   | HouseholdSummary | ||||||
|   | RecipeTag |   | RecipeTag | ||||||
|   | RecipeCategory |   | RecipeCategory | ||||||
|   | RecipeTool |   | RecipeTool | ||||||
|   | IngredientFood |   | IngredientFood | ||||||
|   | string |   | string | ||||||
|       )[] | undefined, | )[] | undefined>({ required: true }); | ||||||
|       required: true, |  | ||||||
|     }, |  | ||||||
|     /** |  | ||||||
|      * The type of organizer to use. |  | ||||||
|      */ |  | ||||||
|     selectorType: { |  | ||||||
|       type: String as () => RecipeOrganizer, |  | ||||||
|       required: true, |  | ||||||
|     }, |  | ||||||
|     inputAttrs: { |  | ||||||
|       type: Object as () => Record<string, any>, |  | ||||||
|       default: () => ({}), |  | ||||||
|     }, |  | ||||||
|     returnObject: { |  | ||||||
|       type: Boolean, |  | ||||||
|       default: true, |  | ||||||
|     }, |  | ||||||
|     showAdd: { |  | ||||||
|       type: Boolean, |  | ||||||
|       default: true, |  | ||||||
|     }, |  | ||||||
|     showLabel: { |  | ||||||
|       type: Boolean, |  | ||||||
|       default: true, |  | ||||||
|     }, |  | ||||||
|     showIcon: { |  | ||||||
|       type: Boolean, |  | ||||||
|       default: true, |  | ||||||
|     }, |  | ||||||
|     variant: { |  | ||||||
|       type: String as () => "filled" | "underlined" | "outlined" | "plain" | "solo" | "solo-inverted" | "solo-filled", |  | ||||||
|       default: "outlined", |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
|   emits: ["update:modelValue"], |  | ||||||
|  |  | ||||||
|   setup(props, context) { |  | ||||||
|     const selected = computed({ |  | ||||||
|       get: () => props.modelValue, |  | ||||||
|       set: (val) => { |  | ||||||
|         context.emit("update:modelValue", val); |  | ||||||
|       }, |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|   if (selected.value === undefined) { |   if (selected.value === undefined) { | ||||||
| @@ -205,21 +178,6 @@ export default defineNuxtComponent({ | |||||||
| function resetSearchInput() { | function resetSearchInput() { | ||||||
|   searchInput.value = ""; |   searchInput.value = ""; | ||||||
| } | } | ||||||
|  |  | ||||||
|     return { |  | ||||||
|       Organizer, |  | ||||||
|       appendCreated, |  | ||||||
|       dialog, |  | ||||||
|       storeItem: items, |  | ||||||
|       label, |  | ||||||
|       icon, |  | ||||||
|       selected, |  | ||||||
|       removeByIndex, |  | ||||||
|       searchInput, |  | ||||||
|       resetSearchInput, |  | ||||||
|     }; |  | ||||||
|   }, |  | ||||||
| }); |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style scoped> | <style scoped> | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ | |||||||
|       @cancel="deleteCreateTarget()" |       @cancel="deleteCreateTarget()" | ||||||
|     > |     > | ||||||
|       <v-card-text> |       <v-card-text> | ||||||
|         <CookbookEditor :key="createTargetKey" v-model="createTarget" :actions="actions" /> |         <CookbookEditor :key="createTargetKey" v-model="createTarget" /> | ||||||
|       </v-card-text> |       </v-card-text> | ||||||
|     </BaseDialog> |     </BaseDialog> | ||||||
|  |  | ||||||
| @@ -105,9 +105,7 @@ | |||||||
|             <v-expansion-panel-text> |             <v-expansion-panel-text> | ||||||
|               <CookbookEditor |               <CookbookEditor | ||||||
|                 v-model="myCookbooks[index]" |                 v-model="myCookbooks[index]" | ||||||
|                 :actions="actions" |  | ||||||
|                 :collapsable="false" |                 :collapsable="false" | ||||||
|                 @delete="deleteEventHandler" |  | ||||||
|               /> |               /> | ||||||
|               <v-card-actions> |               <v-card-actions> | ||||||
|                 <v-spacer /> |                 <v-spacer /> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user