ExtendedRecipeMixin
This commit is contained in:
parent
2fc27d7c36
commit
613b618533
@ -876,7 +876,7 @@ class SearchPreference(models.Model, PermissionModelMixin):
|
|||||||
unaccent = models.ManyToManyField(SearchFields, related_name="unaccent_fields", blank=True, default=allSearchFields)
|
unaccent = models.ManyToManyField(SearchFields, related_name="unaccent_fields", blank=True, default=allSearchFields)
|
||||||
icontains = models.ManyToManyField(SearchFields, related_name="icontains_fields", blank=True, default=nameSearchField)
|
icontains = models.ManyToManyField(SearchFields, related_name="icontains_fields", blank=True, default=nameSearchField)
|
||||||
istartswith = models.ManyToManyField(SearchFields, related_name="istartswith_fields", blank=True)
|
istartswith = models.ManyToManyField(SearchFields, related_name="istartswith_fields", blank=True)
|
||||||
trigram = models.ManyToManyField(SearchFields, related_name="trigram_fields", blank=True,default=nameSearchField)
|
trigram = models.ManyToManyField(SearchFields, related_name="trigram_fields", blank=True, default=nameSearchField)
|
||||||
fulltext = models.ManyToManyField(SearchFields, related_name="fulltext_fields", blank=True)
|
fulltext = models.ManyToManyField(SearchFields, related_name="fulltext_fields", blank=True)
|
||||||
trigram_threshold = models.DecimalField(default=0.1, decimal_places=2, max_digits=3)
|
trigram_threshold = models.DecimalField(default=0.1, decimal_places=2, max_digits=3)
|
||||||
|
|
||||||
|
@ -21,6 +21,45 @@ from cookbook.models import (Comment, CookLog, Food, Ingredient, Keyword,
|
|||||||
from cookbook.templatetags.custom_tags import markdown
|
from cookbook.templatetags.custom_tags import markdown
|
||||||
|
|
||||||
|
|
||||||
|
class ExtendedRecipeMixin(serializers.ModelSerializer):
|
||||||
|
# adds image and recipe count to serializer when query param extended=1
|
||||||
|
image = serializers.SerializerMethodField('get_image')
|
||||||
|
numrecipe = serializers.SerializerMethodField('count_recipes')
|
||||||
|
recipe_filter = None
|
||||||
|
|
||||||
|
def get_fields(self, *args, **kwargs):
|
||||||
|
fields = super().get_fields(*args, **kwargs)
|
||||||
|
try:
|
||||||
|
api_serializer = self.context['view'].serializer_class
|
||||||
|
except KeyError:
|
||||||
|
api_serializer = None
|
||||||
|
# extended values are computationally expensive and not needed in normal circumstances
|
||||||
|
if bool(int(self.context['request'].query_params.get('extended', False))) and self.__class__ == api_serializer:
|
||||||
|
return fields
|
||||||
|
else:
|
||||||
|
del fields['image']
|
||||||
|
del fields['numrecipe']
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def get_image(self, obj):
|
||||||
|
# TODO add caching
|
||||||
|
recipes = Recipe.objects.filter(**{self.recipe_filter: obj}, space=obj.space).exclude(image__isnull=True).exclude(image__exact='')
|
||||||
|
try:
|
||||||
|
if recipes.count() == 0 and obj.has_children():
|
||||||
|
obj__in = self.recipe_filter + '__in'
|
||||||
|
recipes = Recipe.objects.filter(**{obj__in: obj.get_descendants()}, space=obj.space).exclude(image__isnull=True).exclude(image__exact='') # if no recipes found - check whole tree
|
||||||
|
except AttributeError:
|
||||||
|
# probably not a tree
|
||||||
|
pass
|
||||||
|
if recipes.count() != 0:
|
||||||
|
return random.choice(recipes).image.url
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def count_recipes(self, obj):
|
||||||
|
return Recipe.objects.filter(**{self.recipe_filter: obj}, space=obj.space).count()
|
||||||
|
|
||||||
|
|
||||||
class CustomDecimalField(serializers.Field):
|
class CustomDecimalField(serializers.Field):
|
||||||
"""
|
"""
|
||||||
Custom decimal field to normalize useless decimal places
|
Custom decimal field to normalize useless decimal places
|
||||||
@ -28,10 +67,9 @@ class CustomDecimalField(serializers.Field):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def to_representation(self, value):
|
def to_representation(self, value):
|
||||||
if isinstance(value, Decimal):
|
if not isinstance(value, Decimal):
|
||||||
return value.normalize()
|
value = Decimal(value)
|
||||||
else:
|
return round(value, 2).normalize()
|
||||||
return Decimal(value).normalize()
|
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
if type(data) == int or type(data) == float:
|
if type(data) == int or type(data) == float:
|
||||||
@ -206,25 +244,26 @@ class KeywordLabelSerializer(serializers.ModelSerializer):
|
|||||||
read_only_fields = ('id', 'label')
|
read_only_fields = ('id', 'label')
|
||||||
|
|
||||||
|
|
||||||
class KeywordSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
|
class KeywordSerializer(UniqueFieldsMixin, ExtendedRecipeMixin):
|
||||||
label = serializers.SerializerMethodField('get_label')
|
label = serializers.SerializerMethodField('get_label')
|
||||||
image = serializers.SerializerMethodField('get_image')
|
# image = serializers.SerializerMethodField('get_image')
|
||||||
numrecipe = serializers.SerializerMethodField('count_recipes')
|
# numrecipe = serializers.SerializerMethodField('count_recipes')
|
||||||
|
recipe_filter = 'keywords'
|
||||||
|
|
||||||
def get_label(self, obj):
|
def get_label(self, obj):
|
||||||
return str(obj)
|
return str(obj)
|
||||||
|
|
||||||
def get_image(self, obj):
|
# def get_image(self, obj):
|
||||||
recipes = obj.recipe_set.all().filter(space=obj.space).exclude(image__isnull=True).exclude(image__exact='')
|
# recipes = obj.recipe_set.all().filter(space=obj.space).exclude(image__isnull=True).exclude(image__exact='')
|
||||||
if recipes.count() == 0 and obj.has_children():
|
# if recipes.count() == 0 and obj.has_children():
|
||||||
recipes = Recipe.objects.filter(keywords__in=obj.get_descendants(), space=obj.space).exclude(image__isnull=True).exclude(image__exact='') # if no recipes found - check whole tree
|
# recipes = Recipe.objects.filter(keywords__in=obj.get_descendants(), space=obj.space).exclude(image__isnull=True).exclude(image__exact='') # if no recipes found - check whole tree
|
||||||
if recipes.count() != 0:
|
# if recipes.count() != 0:
|
||||||
return random.choice(recipes).image.url
|
# return random.choice(recipes).image.url
|
||||||
else:
|
# else:
|
||||||
return None
|
# return None
|
||||||
|
|
||||||
def count_recipes(self, obj):
|
# def count_recipes(self, obj):
|
||||||
return obj.recipe_set.filter(space=self.context['request'].space).all().count()
|
# return obj.recipe_set.filter(space=self.context['request'].space).all().count()
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
# since multi select tags dont have id's
|
# since multi select tags dont have id's
|
||||||
@ -242,20 +281,21 @@ class KeywordSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
|
|||||||
read_only_fields = ('id', 'numchild', 'parent', 'image')
|
read_only_fields = ('id', 'numchild', 'parent', 'image')
|
||||||
|
|
||||||
|
|
||||||
class UnitSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
|
class UnitSerializer(UniqueFieldsMixin, ExtendedRecipeMixin):
|
||||||
image = serializers.SerializerMethodField('get_image')
|
# image = serializers.SerializerMethodField('get_image')
|
||||||
numrecipe = serializers.SerializerMethodField('count_recipes')
|
# numrecipe = serializers.SerializerMethodField('count_recipes')
|
||||||
|
recipe_filter = 'steps__ingredients__unit'
|
||||||
|
|
||||||
def get_image(self, obj):
|
# def get_image(self, obj):
|
||||||
recipes = Recipe.objects.filter(steps__ingredients__unit=obj, space=obj.space).exclude(image__isnull=True).exclude(image__exact='')
|
# recipes = Recipe.objects.filter(steps__ingredients__unit=obj, space=obj.space).exclude(image__isnull=True).exclude(image__exact='')
|
||||||
|
|
||||||
if recipes.count() != 0:
|
# if recipes.count() != 0:
|
||||||
return random.choice(recipes).image.url
|
# return random.choice(recipes).image.url
|
||||||
else:
|
# else:
|
||||||
return None
|
# return None
|
||||||
|
|
||||||
def count_recipes(self, obj):
|
# def count_recipes(self, obj):
|
||||||
return Recipe.objects.filter(steps__ingredients__unit=obj, space=obj.space).count()
|
# return Recipe.objects.filter(steps__ingredients__unit=obj, space=obj.space).count()
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
validated_data['name'] = validated_data['name'].strip()
|
validated_data['name'] = validated_data['name'].strip()
|
||||||
@ -317,29 +357,30 @@ class RecipeSimpleSerializer(serializers.ModelSerializer):
|
|||||||
read_only_fields = ['id', 'name', 'url']
|
read_only_fields = ['id', 'name', 'url']
|
||||||
|
|
||||||
|
|
||||||
class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedRecipeMixin):
|
||||||
supermarket_category = SupermarketCategorySerializer(allow_null=True, required=False)
|
supermarket_category = SupermarketCategorySerializer(allow_null=True, required=False)
|
||||||
recipe = RecipeSimpleSerializer(allow_null=True, required=False)
|
recipe = RecipeSimpleSerializer(allow_null=True, required=False)
|
||||||
image = serializers.SerializerMethodField('get_image')
|
# image = serializers.SerializerMethodField('get_image')
|
||||||
numrecipe = serializers.SerializerMethodField('count_recipes')
|
# numrecipe = serializers.SerializerMethodField('count_recipes')
|
||||||
|
recipe_filter = 'steps__ingredients__food'
|
||||||
|
|
||||||
def get_image(self, obj):
|
# def get_image(self, obj):
|
||||||
if obj.recipe and obj.space == obj.recipe.space:
|
# if obj.recipe and obj.space == obj.recipe.space:
|
||||||
if obj.recipe.image and obj.recipe.image != '':
|
# if obj.recipe.image and obj.recipe.image != '':
|
||||||
return obj.recipe.image.url
|
# return obj.recipe.image.url
|
||||||
# if food is not also a recipe, look for recipe images that use the food
|
# # if food is not also a recipe, look for recipe images that use the food
|
||||||
recipes = Recipe.objects.filter(steps__ingredients__food=obj, space=obj.space).exclude(image__isnull=True).exclude(image__exact='')
|
# recipes = Recipe.objects.filter(steps__ingredients__food=obj, space=obj.space).exclude(image__isnull=True).exclude(image__exact='')
|
||||||
# if no recipes found - check whole tree
|
# # if no recipes found - check whole tree
|
||||||
if recipes.count() == 0 and obj.has_children():
|
# if recipes.count() == 0 and obj.has_children():
|
||||||
recipes = Recipe.objects.filter(steps__ingredients__food__in=obj.get_descendants(), space=obj.space).exclude(image__isnull=True).exclude(image__exact='')
|
# recipes = Recipe.objects.filter(steps__ingredients__food__in=obj.get_descendants(), space=obj.space).exclude(image__isnull=True).exclude(image__exact='')
|
||||||
|
|
||||||
if recipes.count() != 0:
|
# if recipes.count() != 0:
|
||||||
return random.choice(recipes).image.url
|
# return random.choice(recipes).image.url
|
||||||
else:
|
# else:
|
||||||
return None
|
# return None
|
||||||
|
|
||||||
def count_recipes(self, obj):
|
# def count_recipes(self, obj):
|
||||||
return Recipe.objects.filter(steps__ingredients__food=obj, space=obj.space).count()
|
# return Recipe.objects.filter(steps__ingredients__food=obj, space=obj.space).count()
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
validated_data['name'] = validated_data['name'].strip()
|
validated_data['name'] = validated_data['name'].strip()
|
||||||
@ -561,7 +602,7 @@ class MealPlanSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
|
|||||||
recipe = RecipeOverviewSerializer(required=False, allow_null=True)
|
recipe = RecipeOverviewSerializer(required=False, allow_null=True)
|
||||||
recipe_name = serializers.ReadOnlyField(source='recipe.name')
|
recipe_name = serializers.ReadOnlyField(source='recipe.name')
|
||||||
meal_type = MealTypeSerializer()
|
meal_type = MealTypeSerializer()
|
||||||
meal_type_name = serializers.ReadOnlyField(source='meal_type.name') # TODO deprecate once old meal plan was removed
|
meal_type_name = serializers.ReadOnlyField(source='meal_type.name') # TODO deprecate once old meal plan was removed
|
||||||
note_markdown = serializers.SerializerMethodField('get_note_markdown')
|
note_markdown = serializers.SerializerMethodField('get_note_markdown')
|
||||||
servings = CustomDecimalField()
|
servings = CustomDecimalField()
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -101,7 +101,7 @@ class FuzzyFilterMixin(ViewSetMixin):
|
|||||||
schema = FilterSchema()
|
schema = FilterSchema()
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
self.queryset = self.queryset.filter(space=self.request.space)
|
self.queryset = self.queryset.filter(space=self.request.space).order_by('name')
|
||||||
query = self.request.query_params.get('query', None)
|
query = self.request.query_params.get('query', None)
|
||||||
fuzzy = self.request.user.searchpreference.lookup
|
fuzzy = self.request.user.searchpreference.lookup
|
||||||
|
|
||||||
@ -111,14 +111,14 @@ class FuzzyFilterMixin(ViewSetMixin):
|
|||||||
self.queryset
|
self.queryset
|
||||||
.annotate(exact=Case(When(name__iexact=query, then=(Value(100))), default=Value(0))) # put exact matches at the top of the result set
|
.annotate(exact=Case(When(name__iexact=query, then=(Value(100))), default=Value(0))) # put exact matches at the top of the result set
|
||||||
.annotate(trigram=TrigramSimilarity('name', query)).filter(trigram__gt=0.2)
|
.annotate(trigram=TrigramSimilarity('name', query)).filter(trigram__gt=0.2)
|
||||||
.order_by('-exact').order_by("-trigram")
|
.order_by('-exact', '-trigram')
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# TODO have this check unaccent search settings or other search preferences?
|
# TODO have this check unaccent search settings or other search preferences?
|
||||||
self.queryset = (
|
self.queryset = (
|
||||||
self.queryset
|
self.queryset
|
||||||
.annotate(exact=Case(When(name__iexact=query, then=(Value(100))), default=Value(0))) # put exact matches at the top of the result set
|
.annotate(exact=Case(When(name__iexact=query, then=(Value(100))), default=Value(0))) # put exact matches at the top of the result set
|
||||||
.filter(name__icontains=query).order_by('-exact')
|
.filter(name__icontains=query).order_by('-exact', 'name')
|
||||||
)
|
)
|
||||||
|
|
||||||
updated_at = self.request.query_params.get('updated_at', None)
|
updated_at = self.request.query_params.get('updated_at', None)
|
||||||
@ -139,7 +139,7 @@ class FuzzyFilterMixin(ViewSetMixin):
|
|||||||
return self.queryset
|
return self.queryset
|
||||||
|
|
||||||
|
|
||||||
class MergeMixin(ViewSetMixin): # TODO update Units to use merge API
|
class MergeMixin(ViewSetMixin):
|
||||||
@decorators.action(detail=True, url_path='merge/(?P<target>[^/.]+)', methods=['PUT'], )
|
@decorators.action(detail=True, url_path='merge/(?P<target>[^/.]+)', methods=['PUT'], )
|
||||||
@decorators.renderer_classes((TemplateHTMLRenderer, JSONRenderer))
|
@decorators.renderer_classes((TemplateHTMLRenderer, JSONRenderer))
|
||||||
def merge(self, request, pk, target):
|
def merge(self, request, pk, target):
|
||||||
|
@ -252,6 +252,7 @@ export default {
|
|||||||
},
|
},
|
||||||
getItems: function (params, col) {
|
getItems: function (params, col) {
|
||||||
let column = col || 'left'
|
let column = col || 'left'
|
||||||
|
params.options = {'query':{'extended': 1}} // returns extended values in API response
|
||||||
this.genericAPI(this.this_model, this.Actions.LIST, params).then((result) => {
|
this.genericAPI(this.this_model, this.Actions.LIST, params).then((result) => {
|
||||||
let results = result.data?.results ?? result.data
|
let results = result.data?.results ?? result.data
|
||||||
|
|
||||||
@ -399,11 +400,13 @@ export default {
|
|||||||
},
|
},
|
||||||
getChildren: function (col, item) {
|
getChildren: function (col, item) {
|
||||||
let parent = {}
|
let parent = {}
|
||||||
let options = {
|
let params = {
|
||||||
'root': item.id,
|
'root': item.id,
|
||||||
'pageSize': 200
|
'pageSize': 200,
|
||||||
|
'query': {'extended': 1},
|
||||||
|
'options': {'query':{'extended': 1}}
|
||||||
}
|
}
|
||||||
this.genericAPI(this.this_model, this.Actions.LIST, options).then((result) => {
|
this.genericAPI(this.this_model, this.Actions.LIST, params).then((result) => {
|
||||||
parent = this.findCard(item.id, this['items_' + col])
|
parent = this.findCard(item.id, this['items_' + col])
|
||||||
if (parent) {
|
if (parent) {
|
||||||
Vue.set(parent, 'children', result.data.results)
|
Vue.set(parent, 'children', result.data.results)
|
||||||
@ -418,10 +421,10 @@ export default {
|
|||||||
getRecipes: function (col, item) {
|
getRecipes: function (col, item) {
|
||||||
let parent = {}
|
let parent = {}
|
||||||
// TODO: make this generic
|
// TODO: make this generic
|
||||||
let options = {'pageSize': 200}
|
let params = {'pageSize': 50}
|
||||||
options[this.this_recipe_param] = item.id
|
params[this.this_recipe_param] = item.id
|
||||||
|
|
||||||
this.genericAPI(this.Models.RECIPE, this.Actions.LIST, options).then((result) => {
|
this.genericAPI(this.Models.RECIPE, this.Actions.LIST, params).then((result) => {
|
||||||
parent = this.findCard(item.id, this['items_' + col])
|
parent = this.findCard(item.id, this['items_' + col])
|
||||||
if (parent) {
|
if (parent) {
|
||||||
Vue.set(parent, 'recipes', result.data.results)
|
Vue.set(parent, 'recipes', result.data.results)
|
||||||
|
@ -13,7 +13,7 @@ export class Models {
|
|||||||
// MODEL_TYPES - inherited by MODELS, inherits and takes precedence over ACTIONS
|
// MODEL_TYPES - inherited by MODELS, inherits and takes precedence over ACTIONS
|
||||||
static TREE = {
|
static TREE = {
|
||||||
'list': {
|
'list': {
|
||||||
'params': ['query', 'root', 'tree', 'page', 'pageSize'],
|
'params': ['query', 'root', 'tree', 'page', 'pageSize', 'options'],
|
||||||
'config': {
|
'config': {
|
||||||
'root': {
|
'root': {
|
||||||
'default': {
|
'default': {
|
||||||
@ -471,7 +471,7 @@ export class Actions {
|
|||||||
static LIST = {
|
static LIST = {
|
||||||
"function": "list",
|
"function": "list",
|
||||||
"suffix": "s",
|
"suffix": "s",
|
||||||
"params": ['query', 'page', 'pageSize'],
|
"params": ['query', 'page', 'pageSize', 'options'],
|
||||||
"config": {
|
"config": {
|
||||||
'query': {'default': undefined},
|
'query': {'default': undefined},
|
||||||
'page': {'default': 1},
|
'page': {'default': 1},
|
||||||
|
@ -159,7 +159,7 @@ export function roundDecimals(num) {
|
|||||||
/*
|
/*
|
||||||
* Utility functions to use OpenAPIs generically
|
* Utility functions to use OpenAPIs generically
|
||||||
* */
|
* */
|
||||||
import {ApiApiFactory} from "@/utils/openapi/api.ts"; // TODO: is it possible to only import inside the Mixin?
|
import {ApiApiFactory} from "@/utils/openapi/api.ts";
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
axios.defaults.xsrfCookieName = 'csrftoken'
|
axios.defaults.xsrfCookieName = 'csrftoken'
|
||||||
|
@ -3,87 +3,87 @@
|
|||||||
"assets": {
|
"assets": {
|
||||||
"../../templates/sw.js": {
|
"../../templates/sw.js": {
|
||||||
"name": "../../templates/sw.js",
|
"name": "../../templates/sw.js",
|
||||||
"path": "..\\..\\templates\\sw.js"
|
"path": "../../templates/sw.js"
|
||||||
},
|
},
|
||||||
"js/checklist_view.js": {
|
"js/checklist_view.js": {
|
||||||
"name": "js/checklist_view.js",
|
"name": "js/checklist_view.js",
|
||||||
"path": "js\\checklist_view.js"
|
"path": "js/checklist_view.js"
|
||||||
},
|
},
|
||||||
"js/chunk-2d0da313.js": {
|
"js/chunk-2d0da313.js": {
|
||||||
"name": "js/chunk-2d0da313.js",
|
"name": "js/chunk-2d0da313.js",
|
||||||
"path": "js\\chunk-2d0da313.js"
|
"path": "js/chunk-2d0da313.js"
|
||||||
},
|
},
|
||||||
"css/chunk-vendors.css": {
|
"css/chunk-vendors.css": {
|
||||||
"name": "css/chunk-vendors.css",
|
"name": "css/chunk-vendors.css",
|
||||||
"path": "css\\chunk-vendors.css"
|
"path": "css/chunk-vendors.css"
|
||||||
},
|
},
|
||||||
"js/chunk-vendors.js": {
|
"js/chunk-vendors.js": {
|
||||||
"name": "js/chunk-vendors.js",
|
"name": "js/chunk-vendors.js",
|
||||||
"path": "js\\chunk-vendors.js"
|
"path": "js/chunk-vendors.js"
|
||||||
},
|
},
|
||||||
"css/cookbook_view.css": {
|
"css/cookbook_view.css": {
|
||||||
"name": "css/cookbook_view.css",
|
"name": "css/cookbook_view.css",
|
||||||
"path": "css\\cookbook_view.css"
|
"path": "css/cookbook_view.css"
|
||||||
},
|
},
|
||||||
"js/cookbook_view.js": {
|
"js/cookbook_view.js": {
|
||||||
"name": "js/cookbook_view.js",
|
"name": "js/cookbook_view.js",
|
||||||
"path": "js\\cookbook_view.js"
|
"path": "js/cookbook_view.js"
|
||||||
},
|
},
|
||||||
"css/edit_internal_recipe.css": {
|
"css/edit_internal_recipe.css": {
|
||||||
"name": "css/edit_internal_recipe.css",
|
"name": "css/edit_internal_recipe.css",
|
||||||
"path": "css\\edit_internal_recipe.css"
|
"path": "css/edit_internal_recipe.css"
|
||||||
},
|
},
|
||||||
"js/edit_internal_recipe.js": {
|
"js/edit_internal_recipe.js": {
|
||||||
"name": "js/edit_internal_recipe.js",
|
"name": "js/edit_internal_recipe.js",
|
||||||
"path": "js\\edit_internal_recipe.js"
|
"path": "js/edit_internal_recipe.js"
|
||||||
},
|
},
|
||||||
"js/import_response_view.js": {
|
"js/import_response_view.js": {
|
||||||
"name": "js/import_response_view.js",
|
"name": "js/import_response_view.js",
|
||||||
"path": "js\\import_response_view.js"
|
"path": "js/import_response_view.js"
|
||||||
},
|
},
|
||||||
"css/meal_plan_view.css": {
|
"css/meal_plan_view.css": {
|
||||||
"name": "css/meal_plan_view.css",
|
"name": "css/meal_plan_view.css",
|
||||||
"path": "css\\meal_plan_view.css"
|
"path": "css/meal_plan_view.css"
|
||||||
},
|
},
|
||||||
"js/meal_plan_view.js": {
|
"js/meal_plan_view.js": {
|
||||||
"name": "js/meal_plan_view.js",
|
"name": "js/meal_plan_view.js",
|
||||||
"path": "js\\meal_plan_view.js"
|
"path": "js/meal_plan_view.js"
|
||||||
},
|
},
|
||||||
"css/model_list_view.css": {
|
"css/model_list_view.css": {
|
||||||
"name": "css/model_list_view.css",
|
"name": "css/model_list_view.css",
|
||||||
"path": "css\\model_list_view.css"
|
"path": "css/model_list_view.css"
|
||||||
},
|
},
|
||||||
"js/model_list_view.js": {
|
"js/model_list_view.js": {
|
||||||
"name": "js/model_list_view.js",
|
"name": "js/model_list_view.js",
|
||||||
"path": "js\\model_list_view.js"
|
"path": "js/model_list_view.js"
|
||||||
},
|
},
|
||||||
"js/offline_view.js": {
|
"js/offline_view.js": {
|
||||||
"name": "js/offline_view.js",
|
"name": "js/offline_view.js",
|
||||||
"path": "js\\offline_view.js"
|
"path": "js/offline_view.js"
|
||||||
},
|
},
|
||||||
"css/recipe_search_view.css": {
|
"css/recipe_search_view.css": {
|
||||||
"name": "css/recipe_search_view.css",
|
"name": "css/recipe_search_view.css",
|
||||||
"path": "css\\recipe_search_view.css"
|
"path": "css/recipe_search_view.css"
|
||||||
},
|
},
|
||||||
"js/recipe_search_view.js": {
|
"js/recipe_search_view.js": {
|
||||||
"name": "js/recipe_search_view.js",
|
"name": "js/recipe_search_view.js",
|
||||||
"path": "js\\recipe_search_view.js"
|
"path": "js/recipe_search_view.js"
|
||||||
},
|
},
|
||||||
"css/recipe_view.css": {
|
"css/recipe_view.css": {
|
||||||
"name": "css/recipe_view.css",
|
"name": "css/recipe_view.css",
|
||||||
"path": "css\\recipe_view.css"
|
"path": "css/recipe_view.css"
|
||||||
},
|
},
|
||||||
"js/recipe_view.js": {
|
"js/recipe_view.js": {
|
||||||
"name": "js/recipe_view.js",
|
"name": "js/recipe_view.js",
|
||||||
"path": "js\\recipe_view.js"
|
"path": "js/recipe_view.js"
|
||||||
},
|
},
|
||||||
"js/supermarket_view.js": {
|
"js/supermarket_view.js": {
|
||||||
"name": "js/supermarket_view.js",
|
"name": "js/supermarket_view.js",
|
||||||
"path": "js\\supermarket_view.js"
|
"path": "js/supermarket_view.js"
|
||||||
},
|
},
|
||||||
"js/user_file_view.js": {
|
"js/user_file_view.js": {
|
||||||
"name": "js/user_file_view.js",
|
"name": "js/user_file_view.js",
|
||||||
"path": "js\\user_file_view.js"
|
"path": "js/user_file_view.js"
|
||||||
},
|
},
|
||||||
"recipe_search_view.html": {
|
"recipe_search_view.html": {
|
||||||
"name": "recipe_search_view.html",
|
"name": "recipe_search_view.html",
|
||||||
|
Loading…
Reference in New Issue
Block a user