basic tests with new factories

This commit is contained in:
smilerz 2021-12-08 09:01:20 -06:00
parent b5bf0a4584
commit 8f0c5e21ad
9 changed files with 555 additions and 287 deletions

View File

@ -67,6 +67,9 @@ class TreeManager(MP_NodeManager):
except self.model.DoesNotExist: except self.model.DoesNotExist:
with scopes_disabled(): with scopes_disabled():
try: try:
defaults = kwargs.pop('defaults', None)
if defaults:
kwargs = {**kwargs, **defaults}
# ManyToMany fields can't be set this way, so pop them out to save for later # ManyToMany fields can't be set this way, so pop them out to save for later
fields = [field.name for field in self.model._meta.get_fields() if issubclass(type(field), ManyToManyField)] fields = [field.name for field in self.model._meta.get_fields() if issubclass(type(field), ManyToManyField)]
many_to_many = {field: kwargs.pop(field) for field in list(kwargs) if field in fields} many_to_many = {field: kwargs.pop(field) for field in list(kwargs) if field in fields}

View File

@ -179,7 +179,6 @@ class UserPreferenceSerializer(serializers.ModelSerializer):
'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping', 'food_ignore_default', 'default_delay', 'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping', 'food_ignore_default', 'default_delay',
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days', 'csv_delim', 'csv_prefix' 'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days', 'csv_delim', 'csv_prefix'
) )
# read_only_fields = ['user'] # making user read_only removes it from validated_data, moved read_only attribute to serializer
class UserFileSerializer(serializers.ModelSerializer): class UserFileSerializer(serializers.ModelSerializer):

View File

@ -1,5 +1,6 @@
import json import json
import factory
import pytest import pytest
from django.contrib import auth from django.contrib import auth
from django.forms import model_to_dict from django.forms import model_to_dict
@ -13,15 +14,14 @@ from cookbook.tests.factories import FoodFactory, ShoppingListEntryFactory
LIST_URL = 'api:shoppinglistentry-list' LIST_URL = 'api:shoppinglistentry-list'
DETAIL_URL = 'api:shoppinglistentry-detail' DETAIL_URL = 'api:shoppinglistentry-detail'
# register(FoodFactory, 'food_1', space=LazyFixture('space_1'))
# register(FoodFactory, 'food_2', space=LazyFixture('space_1')) @pytest.fixture
# register(ShoppingListEntryFactory, 'sle_1', space=LazyFixture('space_1'), food=LazyFixture('food_1')) def sle(space_1, u1_s1):
# register(ShoppingListEntryFactory, 'sle_2', space=LazyFixture('space_1'), food=LazyFixture('food_2')) user = auth.get_user(u1_s1)
register(ShoppingListEntryFactory, 'sle_1', space=LazyFixture('space_1')) return ShoppingListEntryFactory.create_batch(10, space=space_1, created_by=user)
register(ShoppingListEntryFactory, 'sle_2', space=LazyFixture('space_1'))
@pytest.mark.parametrize("arg", [ @ pytest.mark.parametrize("arg", [
['a_u', 403], ['a_u', 403],
['g1_s1', 200], ['g1_s1', 200],
['u1_s1', 200], ['u1_s1', 200],
@ -32,29 +32,28 @@ def test_list_permission(arg, request):
assert c.get(reverse(LIST_URL)).status_code == arg[1] assert c.get(reverse(LIST_URL)).status_code == arg[1]
def test_list_space(sle_1, u1_s1, u1_s2, space_2): def test_list_space(sle, u1_s1, u1_s2, space_2):
assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 2 assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 10
assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0
with scopes_disabled(): with scopes_disabled():
e = ShoppingListEntry.objects.first() e = ShoppingListEntry.objects.first()
e.space = space_2 e.space = space_2
e.save() e.save()
assert json.loads(u1_s1.get(reverse(LIST_URL)).content)['count'] == 1 assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 9
assert json.loads(u1_s2.get(reverse(LIST_URL)).content)['count'] == 0 assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0
def test_get_detail(u1_s1, sle_1): def test_get_detail(u1_s1, sle):
# r = u1_s1.get(reverse( r = u1_s1.get(reverse(
# DETAIL_URL, DETAIL_URL,
# args={sle_1.id} args={sle[0].id}
# )) ))
# assert json.loads(r.content)['id'] == sle_1.id assert json.loads(r.content)['id'] == sle[0].id
pass
@pytest.mark.parametrize("arg", [ @ pytest.mark.parametrize("arg", [
['a_u', 403], ['a_u', 403],
['g1_s1', 404], ['g1_s1', 404],
['u1_s1', 200], ['u1_s1', 200],
@ -63,20 +62,21 @@ def test_get_detail(u1_s1, sle_1):
['u1_s2', 404], ['u1_s2', 404],
['a1_s2', 404], ['a1_s2', 404],
]) ])
def test_update(arg, request, sle_1): def test_update(arg, request, sle):
c = request.getfixturevalue(arg[0]) c = request.getfixturevalue(arg[0])
new_val = float(sle[0].amount + 1)
r = c.patch( r = c.patch(
reverse( reverse(
DETAIL_URL, DETAIL_URL,
args={sle_1.id} args={sle[0].id}
), ),
{'amount': 2}, {'amount': new_val},
content_type='application/json' content_type='application/json'
) )
assert r.status_code == arg[1] assert r.status_code == arg[1]
if r.status_code == 200: if r.status_code == 200:
response = json.loads(r.content) response = json.loads(r.content)
assert response['amount'] == 2 assert response['amount'] == new_val
@pytest.mark.parametrize("arg", [ @pytest.mark.parametrize("arg", [
@ -85,25 +85,25 @@ def test_update(arg, request, sle_1):
['u1_s1', 201], ['u1_s1', 201],
['a1_s1', 201], ['a1_s1', 201],
]) ])
def test_add(arg, request, sle_1): def test_add(arg, request, sle):
c = request.getfixturevalue(arg[0]) c = request.getfixturevalue(arg[0])
r = c.post( r = c.post(
reverse(LIST_URL), reverse(LIST_URL),
{'food': model_to_dict(sle_1.food), 'amount': 1}, {'food': model_to_dict(sle[0].food), 'amount': 1},
content_type='application/json' content_type='application/json'
) )
response = json.loads(r.content) response = json.loads(r.content)
print(r.content) print(r.content)
assert r.status_code == arg[1] assert r.status_code == arg[1]
if r.status_code == 201: if r.status_code == 201:
assert response['food']['id'] == sle_1.food.pk assert response['food']['id'] == sle[0].food.pk
def test_delete(u1_s1, u1_s2, sle_1): def test_delete(u1_s1, u1_s2, sle):
r = u1_s2.delete( r = u1_s2.delete(
reverse( reverse(
DETAIL_URL, DETAIL_URL,
args={sle_1.id} args={sle[0].id}
) )
) )
assert r.status_code == 404 assert r.status_code == 404
@ -111,7 +111,7 @@ def test_delete(u1_s1, u1_s2, sle_1):
r = u1_s1.delete( r = u1_s1.delete(
reverse( reverse(
DETAIL_URL, DETAIL_URL,
args={sle_1.id} args={sle[0].id}
) )
) )

View File

@ -7,14 +7,14 @@ import pytest
from django.contrib import auth from django.contrib import auth
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from django_scopes import scopes_disabled from django_scopes import scopes_disabled
from pytest_factoryboy import register from pytest_factoryboy import LazyFixture, register
from cookbook.models import Food, Ingredient, Recipe, Space, Step, Unit from cookbook.models import Food, Ingredient, Recipe, Space, Step, Unit
from cookbook.tests.factories import SpaceFactory from cookbook.tests.factories import FoodFactory, SpaceFactory, UserFactory
register(SpaceFactory, 'space_1') register(SpaceFactory, 'space_1')
register(SpaceFactory, 'space_2') register(SpaceFactory, 'space_2')
# register(FoodFactory, space=LazyFixture('space_2'))
# TODO refactor user fixtures https://stackoverflow.com/questions/40966571/how-to-create-a-field-with-a-list-of-instances-in-factory-boy # TODO refactor user fixtures https://stackoverflow.com/questions/40966571/how-to-create-a-field-with-a-list-of-instances-in-factory-boy
# hack from https://github.com/raphaelm/django-scopes to disable scopes for all fixtures # hack from https://github.com/raphaelm/django-scopes to disable scopes for all fixtures
@ -184,25 +184,17 @@ def create_user(client, space, **kwargs):
c = copy.deepcopy(client) c = copy.deepcopy(client)
with scopes_disabled(): with scopes_disabled():
group = kwargs.pop('group', None) group = kwargs.pop('group', None)
username = kwargs.pop('username', uuid.uuid4()) user = UserFactory(space=space, groups=group)
user = User.objects.create(username=username, **kwargs)
if group:
user.groups.add(Group.objects.get(name=group))
user.userpreference.space = space
user.userpreference.save()
c.force_login(user) c.force_login(user)
return c return c
# anonymous user
@pytest.fixture() @pytest.fixture()
def a_u(client): def a_u(client):
return copy.deepcopy(client) return copy.deepcopy(client)
# users without any group
@pytest.fixture() @pytest.fixture()
def ng1_s1(client, space_1): def ng1_s1(client, space_1):
return create_user(client, space_1) return create_user(client, space_1)

View File

@ -4,9 +4,10 @@ from decimal import Decimal
import factory import factory
import pytest import pytest
from django.contrib import auth from django.contrib import auth
from django.contrib.auth.models import User from django.contrib.auth.models import Group, User
from django_scopes import scopes_disabled from django_scopes import scopes_disabled
from faker import Factory as FakerFactory from faker import Factory as FakerFactory
from pytest_factoryboy import register
# this code will run immediately prior to creating the model object useful when you want a reverse relationship # this code will run immediately prior to creating the model object useful when you want a reverse relationship
# log = factory.RelatedFactory( # log = factory.RelatedFactory(
@ -31,6 +32,7 @@ def pytest_fixture_setup(fixturedef, request):
yield yield
@register
class SpaceFactory(factory.django.DjangoModelFactory): class SpaceFactory(factory.django.DjangoModelFactory):
"""Space factory.""" """Space factory."""
name = factory.LazyAttribute(lambda x: faker.word()) name = factory.LazyAttribute(lambda x: faker.word())
@ -44,18 +46,41 @@ class SpaceFactory(factory.django.DjangoModelFactory):
model = 'cookbook.Space' model = 'cookbook.Space'
@register
class UserFactory(factory.django.DjangoModelFactory): class UserFactory(factory.django.DjangoModelFactory):
"""User factory.""" """User factory."""
username = factory.LazyAttribute(lambda x: faker.word()) username = factory.LazyAttribute(lambda x: faker.simple_profile()['username'])
first_name = factory.LazyAttribute(lambda x: faker.first_name()) first_name = factory.LazyAttribute(lambda x: faker.first_name())
last_name = factory.LazyAttribute(lambda x: faker.last_name()) last_name = factory.LazyAttribute(lambda x: faker.last_name())
email = factory.LazyAttribute(lambda x: faker.email()) email = factory.LazyAttribute(lambda x: faker.email())
space = factory.SubFactory(SpaceFactory) space = factory.SubFactory(SpaceFactory)
@factory.post_generation
def groups(self, create, extracted, **kwargs):
if not create:
return
if extracted:
self.groups.add(Group.objects.get(name=extracted))
@factory.post_generation
def userpreference(self, create, extracted, **kwargs):
if not create:
return
if extracted:
# TODO this doesn't work and needs saved
for prefs in extracted:
self.userpreference[prefs] = prefs
self.userpreference.space = self.space
self.userpreference.save()
class Meta: class Meta:
model = User model = User
@register
class SupermarketCategoryFactory(factory.django.DjangoModelFactory): class SupermarketCategoryFactory(factory.django.DjangoModelFactory):
"""SupermarketCategory factory.""" """SupermarketCategory factory."""
name = factory.LazyAttribute(lambda x: faker.word()) name = factory.LazyAttribute(lambda x: faker.word())
@ -64,9 +89,11 @@ class SupermarketCategoryFactory(factory.django.DjangoModelFactory):
class Meta: class Meta:
model = 'cookbook.SupermarketCategory' model = 'cookbook.SupermarketCategory'
django_get_or_create = ('name', 'space',)
# @factory.django.mute_signals(post_save) # @factory.django.mute_signals(post_save)
@register
class FoodFactory(factory.django.DjangoModelFactory): class FoodFactory(factory.django.DjangoModelFactory):
"""Food factory.""" """Food factory."""
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3)) name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3))
@ -89,8 +116,10 @@ class FoodFactory(factory.django.DjangoModelFactory):
class Meta: class Meta:
model = 'cookbook.Food' model = 'cookbook.Food'
django_get_or_create = ('name', 'space',)
@register
class UnitFactory(factory.django.DjangoModelFactory): class UnitFactory(factory.django.DjangoModelFactory):
"""Unit factory.""" """Unit factory."""
name = factory.LazyAttribute(lambda x: faker.word()) name = factory.LazyAttribute(lambda x: faker.word())
@ -99,8 +128,10 @@ class UnitFactory(factory.django.DjangoModelFactory):
class Meta: class Meta:
model = 'cookbook.Unit' model = 'cookbook.Unit'
django_get_or_create = ('name', 'space',)
@register
class KeywordFactory(factory.django.DjangoModelFactory): class KeywordFactory(factory.django.DjangoModelFactory):
"""Keyword factory.""" """Keyword factory."""
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3)) name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=3))
@ -110,8 +141,10 @@ class KeywordFactory(factory.django.DjangoModelFactory):
class Meta: class Meta:
model = 'cookbook.Keyword' model = 'cookbook.Keyword'
django_get_or_create = ('name', 'space',)
@register
class IngredientFactory(factory.django.DjangoModelFactory): class IngredientFactory(factory.django.DjangoModelFactory):
"""Ingredient factory.""" """Ingredient factory."""
food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space')) food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space'))
@ -124,6 +157,7 @@ class IngredientFactory(factory.django.DjangoModelFactory):
model = 'cookbook.Ingredient' model = 'cookbook.Ingredient'
@register
class MealTypeFactory(factory.django.DjangoModelFactory): class MealTypeFactory(factory.django.DjangoModelFactory):
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5)) name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5))
order = 0 order = 0
@ -137,6 +171,7 @@ class MealTypeFactory(factory.django.DjangoModelFactory):
model = 'cookbook.MealType' model = 'cookbook.MealType'
@register
class MealPlanFactory(factory.django.DjangoModelFactory): class MealPlanFactory(factory.django.DjangoModelFactory):
recipe = factory.Maybe( recipe = factory.Maybe(
factory.LazyAttribute(lambda x: x.has_recipe), factory.LazyAttribute(lambda x: x.has_recipe),
@ -158,6 +193,7 @@ class MealPlanFactory(factory.django.DjangoModelFactory):
model = 'cookbook.MealPlan' model = 'cookbook.MealPlan'
@register
class ShoppingListRecipeFactory(factory.django.DjangoModelFactory): class ShoppingListRecipeFactory(factory.django.DjangoModelFactory):
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5)) name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5))
recipe = factory.Maybe( recipe = factory.Maybe(
@ -175,6 +211,7 @@ class ShoppingListRecipeFactory(factory.django.DjangoModelFactory):
model = 'cookbook.ShoppingListRecipe' model = 'cookbook.ShoppingListRecipe'
@register
class ShoppingListEntryFactory(factory.django.DjangoModelFactory): class ShoppingListEntryFactory(factory.django.DjangoModelFactory):
"""ShoppingListEntry factory.""" """ShoppingListEntry factory."""
@ -184,16 +221,16 @@ class ShoppingListEntryFactory(factory.django.DjangoModelFactory):
no_declaration=None no_declaration=None
) )
food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space')) food = factory.SubFactory(FoodFactory, space=factory.SelfAttribute('..space'))
# unit = factory.SubFactory(UnitFactory, space=factory.SelfAttribute('..space')) unit = factory.SubFactory(UnitFactory, space=factory.SelfAttribute('..space'))
# # ingredient = factory.SubFactory(IngredientFactory) # # ingredient = factory.SubFactory(IngredientFactory)
amount = factory.LazyAttribute(lambda x: Decimal(faker.random_int(min=1, max=10))/100) amount = factory.LazyAttribute(lambda x: Decimal(faker.random_int(min=1, max=100))/10)
order = 0 order = factory.Sequence(int)
checked = False checked = False
created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space')) created_by = factory.SubFactory(UserFactory, space=factory.SelfAttribute('..space'))
created_at = factory.LazyAttribute(lambda x: faker.past_date()) created_at = factory.LazyAttribute(lambda x: faker.past_date())
completed_at = None completed_at = None
delay_until = None delay_until = None
space = factory.SubFactory('cookbook.tests.factories.SpaceFactory') space = factory.SubFactory(SpaceFactory)
class Params: class Params:
has_mealplan = False has_mealplan = False
@ -202,6 +239,7 @@ class ShoppingListEntryFactory(factory.django.DjangoModelFactory):
model = 'cookbook.ShoppingListEntry' model = 'cookbook.ShoppingListEntry'
@register
class StepFactory(factory.django.DjangoModelFactory): class StepFactory(factory.django.DjangoModelFactory):
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5)) name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=5))
# type = models.CharField( # type = models.CharField(
@ -229,6 +267,7 @@ class StepFactory(factory.django.DjangoModelFactory):
model = 'cookbook.Step' model = 'cookbook.Step'
@register
class RecipeFactory(factory.django.DjangoModelFactory): class RecipeFactory(factory.django.DjangoModelFactory):
name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=7)) name = factory.LazyAttribute(lambda x: faker.sentence(nb_words=7))
description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10)) description = factory.LazyAttribute(lambda x: faker.sentence(nb_words=10))

487
vue/package-lock.json generated
View File

@ -1282,6 +1282,11 @@
} }
} }
}, },
"@popperjs/core": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz",
"integrity": "sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ=="
},
"@riophae/vue-treeselect": { "@riophae/vue-treeselect": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/@riophae/vue-treeselect/-/vue-treeselect-0.4.0.tgz", "resolved": "https://registry.npmjs.org/@riophae/vue-treeselect/-/vue-treeselect-0.4.0.tgz",
@ -2398,6 +2403,116 @@
"tslint": "^5.20.1", "tslint": "^5.20.1",
"webpack": "^4.0.0", "webpack": "^4.0.0",
"yorkie": "^2.0.0" "yorkie": "^2.0.0"
},
"dependencies": {
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"cosmiconfig": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
"integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
"dev": true,
"optional": true,
"requires": {
"@types/parse-json": "^4.0.0",
"import-fresh": "^3.1.0",
"parse-json": "^5.0.0",
"path-type": "^4.0.0",
"yaml": "^1.7.2"
}
},
"fork-ts-checker-webpack-plugin-v5": {
"version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
"integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
"dev": true,
"optional": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@types/json-schema": "^7.0.5",
"chalk": "^4.1.0",
"cosmiconfig": "^6.0.0",
"deepmerge": "^4.2.2",
"fs-extra": "^9.0.0",
"memfs": "^3.1.2",
"minimatch": "^3.0.4",
"schema-utils": "2.7.0",
"semver": "^7.3.2",
"tapable": "^1.0.0"
}
},
"fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dev": true,
"optional": true,
"requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
}
},
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"optional": true,
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"optional": true,
"requires": {
"yallist": "^4.0.0"
}
},
"schema-utils": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
"dev": true,
"optional": true,
"requires": {
"@types/json-schema": "^7.0.4",
"ajv": "^6.12.2",
"ajv-keywords": "^3.4.1"
}
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"optional": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
"dev": true,
"optional": true
}
} }
}, },
"@vue/cli-plugin-vuex": { "@vue/cli-plugin-vuex": {
@ -2470,6 +2585,17 @@
"webpack-merge": "^4.2.2" "webpack-merge": "^4.2.2"
}, },
"dependencies": { "dependencies": {
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"cliui": { "cliui": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
@ -2487,6 +2613,30 @@
"integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==",
"dev": true "dev": true
}, },
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
}
},
"wrap-ansi": { "wrap-ansi": {
"version": "6.2.0", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@ -2637,6 +2787,15 @@
"vue-template-es2015-compiler": "^1.9.0" "vue-template-es2015-compiler": "^1.9.0"
} }
}, },
"@vue/eslint-config-typescript": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-9.1.0.tgz",
"integrity": "sha512-j/852/ZYQ5wDvCD3HE2q4uqJwJAceer2FwoEch1nFo+zTOsPrbzbE3cuWIs3kvu5hdFsGTMYwRwjI6fqZKDMxQ==",
"dev": true,
"requires": {
"vue-eslint-parser": "^8.0.0"
}
},
"@vue/preload-webpack-plugin": { "@vue/preload-webpack-plugin": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.2.tgz",
@ -3215,6 +3374,14 @@
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
"dev": true "dev": true
}, },
"axios": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
"requires": {
"follow-redirects": "^1.14.4"
}
},
"babel-code-frame": { "babel-code-frame": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@ -4757,6 +4924,11 @@
} }
} }
}, },
"core-js": {
"version": "3.19.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.3.tgz",
"integrity": "sha512-LeLBMgEGSsG7giquSzvgBrTS7V5UL6ks3eQlUSbN8dJStlLFiRzUm5iqsRyzUB8carhfKjkJ2vzKqE6z1Vga9g=="
},
"core-js-compat": { "core-js-compat": {
"version": "3.19.2", "version": "3.19.2",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.2.tgz", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.2.tgz",
@ -6534,9 +6706,9 @@
} }
}, },
"eslint-plugin-vue": { "eslint-plugin-vue": {
"version": "8.1.1", "version": "8.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.1.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.2.0.tgz",
"integrity": "sha512-rx64IrlhdfPya6u2V5ukOGiLCTgaCBdMSpczLVqyo8A0l+Vbo+lzvIfEUfAQ2auj+MF6y0TwxLorzdCIzHunnw==", "integrity": "sha512-cLIdTuOAMXyHeQ4drYKcZfoyzdwdBpH279X8/N0DgmotEI9yFKb5O/cAgoie/CkQZCH/MOmh0xw/KEfS90zY2A==",
"dev": true, "dev": true,
"requires": { "requires": {
"eslint-utils": "^3.0.0", "eslint-utils": "^3.0.0",
@ -6545,39 +6717,6 @@
"vue-eslint-parser": "^8.0.1" "vue-eslint-parser": "^8.0.1"
}, },
"dependencies": { "dependencies": {
"acorn": {
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz",
"integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==",
"dev": true
},
"eslint-scope": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz",
"integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==",
"dev": true,
"requires": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
}
},
"eslint-visitor-keys": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz",
"integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==",
"dev": true
},
"espree": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.1.0.tgz",
"integrity": "sha512-ZgYLvCS1wxOczBYGcQT9DDWgicXwJ4dbocr9uYN+/eresBAUuBu+O4WzB21ufQ/JqQT8gyp7hJ3z8SHii32mTQ==",
"dev": true,
"requires": {
"acorn": "^8.6.0",
"acorn-jsx": "^5.3.1",
"eslint-visitor-keys": "^3.1.0"
}
},
"lru-cache": { "lru-cache": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@ -6595,29 +6734,6 @@
"requires": { "requires": {
"lru-cache": "^6.0.0" "lru-cache": "^6.0.0"
} }
},
"vue-eslint-parser": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.0.1.tgz",
"integrity": "sha512-lhWjDXJhe3UZw2uu3ztX51SJAPGPey1Tff2RK3TyZURwbuI4vximQLzz4nQfCv8CZq4xx7uIiogHMMoSJPr33A==",
"dev": true,
"requires": {
"debug": "^4.3.2",
"eslint-scope": "^6.0.0",
"eslint-visitor-keys": "^3.0.0",
"espree": "^9.0.0",
"esquery": "^1.4.0",
"lodash": "^4.17.21",
"semver": "^7.3.5"
},
"dependencies": {
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
}
}
} }
} }
}, },
@ -7250,8 +7366,7 @@
"follow-redirects": { "follow-redirects": {
"version": "1.14.5", "version": "1.14.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==", "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA=="
"dev": true
}, },
"for-in": { "for-in": {
"version": "1.0.2", "version": "1.0.2",
@ -7370,116 +7485,6 @@
} }
} }
}, },
"fork-ts-checker-webpack-plugin-v5": {
"version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
"integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
"dev": true,
"optional": true,
"requires": {
"@babel/code-frame": "^7.8.3",
"@types/json-schema": "^7.0.5",
"chalk": "^4.1.0",
"cosmiconfig": "^6.0.0",
"deepmerge": "^4.2.2",
"fs-extra": "^9.0.0",
"memfs": "^3.1.2",
"minimatch": "^3.0.4",
"schema-utils": "2.7.0",
"semver": "^7.3.2",
"tapable": "^1.0.0"
},
"dependencies": {
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"cosmiconfig": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
"integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
"dev": true,
"optional": true,
"requires": {
"@types/parse-json": "^4.0.0",
"import-fresh": "^3.1.0",
"parse-json": "^5.0.0",
"path-type": "^4.0.0",
"yaml": "^1.7.2"
}
},
"fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dev": true,
"optional": true,
"requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
}
},
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"optional": true,
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"optional": true,
"requires": {
"yallist": "^4.0.0"
}
},
"schema-utils": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
"dev": true,
"optional": true,
"requires": {
"@types/json-schema": "^7.0.4",
"ajv": "^6.12.2",
"ajv-keywords": "^3.4.1"
}
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"optional": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
"dev": true,
"optional": true
}
}
},
"form-data": { "form-data": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
@ -9139,6 +9144,11 @@
"path-exists": "^3.0.0" "path-exists": "^3.0.0"
} }
}, },
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash._reinterpolate": { "lodash._reinterpolate": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
@ -11064,6 +11074,11 @@
} }
} }
}, },
"prismjs": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz",
"integrity": "sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg=="
},
"process": { "process": {
"version": "0.11.10", "version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@ -13537,6 +13552,11 @@
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
}, },
"vue": {
"version": "2.6.14",
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
},
"vue-class-component": { "vue-class-component": {
"version": "7.2.6", "version": "7.2.6",
"resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-7.2.6.tgz", "resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-7.2.6.tgz",
@ -13586,11 +13606,87 @@
"resolved": "https://registry.npmjs.org/vue-click-outside/-/vue-click-outside-1.1.0.tgz", "resolved": "https://registry.npmjs.org/vue-click-outside/-/vue-click-outside-1.1.0.tgz",
"integrity": "sha512-pNyvAA9mRXJwPHlHJyjMb4IONSc7khS5lxGcMyE2EIKgNMAO279PWM9Hyq0d5J4FkiSRdmFLwnbjDd5UtPizHQ==" "integrity": "sha512-pNyvAA9mRXJwPHlHJyjMb4IONSc7khS5lxGcMyE2EIKgNMAO279PWM9Hyq0d5J4FkiSRdmFLwnbjDd5UtPizHQ=="
}, },
"vue-clickaway": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/vue-clickaway/-/vue-clickaway-2.2.2.tgz",
"integrity": "sha512-25SpjXKetL06GLYoLoC8pqAV6Cur9cQ//2g35GRFBV4FgoljbZZjTINR8g2NuVXXDMLSUXaKx5dutgO4PaDE7A==",
"requires": {
"loose-envify": "^1.2.0"
}
},
"vue-cookies": { "vue-cookies": {
"version": "1.7.4", "version": "1.7.4",
"resolved": "https://registry.npmjs.org/vue-cookies/-/vue-cookies-1.7.4.tgz", "resolved": "https://registry.npmjs.org/vue-cookies/-/vue-cookies-1.7.4.tgz",
"integrity": "sha512-mOS5Btr8V9zvAtkmQ7/TfqJIropOx7etDAgBywPCmHjvfJl2gFbH2XgoMghleLoyyMTi5eaJss0mPN7arMoslA==" "integrity": "sha512-mOS5Btr8V9zvAtkmQ7/TfqJIropOx7etDAgBywPCmHjvfJl2gFbH2XgoMghleLoyyMTi5eaJss0mPN7arMoslA=="
}, },
"vue-eslint-parser": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.0.1.tgz",
"integrity": "sha512-lhWjDXJhe3UZw2uu3ztX51SJAPGPey1Tff2RK3TyZURwbuI4vximQLzz4nQfCv8CZq4xx7uIiogHMMoSJPr33A==",
"dev": true,
"requires": {
"debug": "^4.3.2",
"eslint-scope": "^6.0.0",
"eslint-visitor-keys": "^3.0.0",
"espree": "^9.0.0",
"esquery": "^1.4.0",
"lodash": "^4.17.21",
"semver": "^7.3.5"
},
"dependencies": {
"acorn": {
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz",
"integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==",
"dev": true
},
"eslint-scope": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz",
"integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==",
"dev": true,
"requires": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
}
},
"eslint-visitor-keys": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz",
"integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==",
"dev": true
},
"espree": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.2.0.tgz",
"integrity": "sha512-oP3utRkynpZWF/F2x/HZJ+AGtnIclaR7z1pYPxy7NYM2fSO6LgK/Rkny8anRSPK/VwEA1eqm2squui0T7ZMOBg==",
"dev": true,
"requires": {
"acorn": "^8.6.0",
"acorn-jsx": "^5.3.1",
"eslint-visitor-keys": "^3.1.0"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
}
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
}
}
},
"vue-functional-data-merge": { "vue-functional-data-merge": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz", "resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz",
@ -13602,6 +13698,11 @@
"integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
"dev": true "dev": true
}, },
"vue-i18n": {
"version": "8.26.7",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.26.7.tgz",
"integrity": "sha512-7apa5PvRg1YCLoraE3lOgpCG8hJGupLCtywQWedWsgBbvF0TOgFvhitqK9xRH0PBGG1G8aiJz9oklyNDFfDxLg=="
},
"vue-i18n-extract": { "vue-i18n-extract": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/vue-i18n-extract/-/vue-i18n-extract-1.0.2.tgz", "resolved": "https://registry.npmjs.org/vue-i18n-extract/-/vue-i18n-extract-1.0.2.tgz",
@ -13634,50 +13735,6 @@
"vue-style-loader": "^4.1.0" "vue-style-loader": "^4.1.0"
} }
}, },
"vue-loader-v16": {
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
},
"dependencies": {
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"hash-sum": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz",
"integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==",
"dev": true,
"optional": true
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
}
}
},
"vue-multiselect": { "vue-multiselect": {
"version": "2.1.6", "version": "2.1.6",
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.6.tgz", "resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.6.tgz",

View File

@ -25,7 +25,7 @@
</div> </div>
<div style="text-align: center"> <div style="text-align: center">
<keywords-component :recipe="recipe" /> <keywords-component :recipe="recipe"></keywords-component>
</div> </div>
<hr /> <hr />
@ -57,21 +57,32 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<br/> <div class="col col-md-4 col-10 mt-2 mt-md-0 mt-lg-0 mt-xl-0">
<template v-for="s in recipe.steps" v-bind:key="s.id"> <div class="row d-flex" style="padding-left: 16px">
<div class="row" > <div class="my-auto" style="padding-right: 4px">
<div class="col-md-12"> <i class="fas fa-pizza-slice fa-2x text-primary"></i>
<template v-if="s.show_as_header && s.name !== '' && s.ingredients.length > 0"> </div>
<b v-bind:key="s.id">{{s.name}}</b> <div class="my-auto" style="padding-right: 4px">
</template> <input
<table class="table table-sm"> style="text-align: right; border-width: 0px; border: none; padding: 0px; padding-left: 0.5vw; padding-right: 8px; max-width: 80px"
<template v-for="i in s.ingredients" :key="i.id"> value="1"
<ingredient-component :ingredient="i" :ingredient_factor="ingredient_factor" maxlength="3"
@checked-state-changed="updateIngredientCheckedState"></ingredient-component> min="0"
</template> type="number"
</table> class="form-control form-control-lg"
</div> v-model.number="servings"
/>
</div>
<div class="my-auto">
<span class="text-primary"
><b
><template v-if="recipe.servings_text === ''">{{ $t("Servings") }}</template
><template v-else>{{ recipe.servings_text }}</template></b
></span
>
</div>
</div>
</div> </div>
<div class="col col-md-2 col-2 my-auto" style="text-align: right; padding-right: 1vw"> <div class="col col-md-2 col-2 my-auto" style="text-align: right; padding-right: 1vw">
@ -82,7 +93,30 @@
<div class="row"> <div class="row">
<div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2" v-if="recipe && ingredient_count > 0"> <div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2" v-if="recipe && ingredient_count > 0">
<ingredients-card :steps="recipe.steps" :ingredient_factor="ingredient_factor" :servings="servings" :header="true" @checked-state-changed="updateIngredientCheckedState" /> <div class="card border-primary">
<div class="card-body">
<div class="row">
<div class="col col-md-8">
<h4 class="card-title"><i class="fas fa-pepper-hot"></i> {{ $t("Ingredients") }}</h4>
</div>
</div>
<br />
<template v-for="s in recipe.steps" v-bind:key="s.id">
<div class="row">
<div class="col-md-12">
<template v-if="s.show_as_header && s.name !== '' && s.ingredients.length > 0">
<b v-bind:key="s.id">{{ s.name }}</b>
</template>
<table class="table table-sm">
<template v-for="i in s.ingredients" :key="i.id">
<ingredient-component :ingredient="i" :ingredient_factor="ingredient_factor" @checked-state-changed="updateIngredientCheckedState"></ingredient-component>
</template>
</table>
</div>
</div>
</template>
</div>
</div>
</div> </div>
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2"> <div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2">
@ -139,21 +173,25 @@ import "bootstrap-vue/dist/bootstrap-vue.css"
import { apiLoadRecipe } from "@/utils/api" import { apiLoadRecipe } from "@/utils/api"
import StepComponent from "@/components/StepComponent" import Step from "@/components/StepComponent"
import RecipeContextMenu from "@/components/RecipeContextMenu" import RecipeContextMenu from "@/components/RecipeContextMenu"
import { ResolveUrlMixin, ToastMixin } from "@/utils/utils" import { ResolveUrlMixin, ToastMixin } from "@/utils/utils"
import Ingredient from "@/components/IngredientComponent"
import PdfViewer from "@/components/PdfViewer" import PdfViewer from "@/components/PdfViewer"
import ImageViewer from "@/components/ImageViewer" import ImageViewer from "@/components/ImageViewer"
import IngredientsCard from "@/components/IngredientsCard" import Nutrition from "@/components/NutritionComponent"
import moment from "moment" import moment from "moment"
import KeywordsComponent from "@/components/KeywordsComponent" import Keywords from "@/components/KeywordsComponent"
import NutritionComponent from "@/components/NutritionComponent"
import LoadingSpinner from "@/components/LoadingSpinner" import LoadingSpinner from "@/components/LoadingSpinner"
import AddRecipeToBook from "@/components/Modals/AddRecipeToBook" import AddRecipeToBook from "@/components/AddRecipeToBook"
import RecipeRating from "@/components/RecipeRating" import RecipeRating from "@/components/RecipeRating"
import LastCooked from "@/components/LastCooked" import LastCooked from "@/components/LastCooked"
import IngredientComponent from "@/components/IngredientComponent"
import StepComponent from "@/components/StepComponent"
import KeywordsComponent from "@/components/KeywordsComponent"
import NutritionComponent from "@/components/NutritionComponent"
Vue.prototype.moment = moment Vue.prototype.moment = moment
@ -167,7 +205,7 @@ export default {
RecipeRating, RecipeRating,
PdfViewer, PdfViewer,
ImageViewer, ImageViewer,
IngredientsCard, IngredientComponent,
StepComponent, StepComponent,
RecipeContextMenu, RecipeContextMenu,
NutritionComponent, NutritionComponent,

View File

@ -0,0 +1,122 @@
<template>
<div>
<b-modal class="modal" :id="`id_modal_add_book_${modal_id}`" :title="$t('Manage_Books')" :ok-title="$t('Add')"
:cancel-title="$t('Close')" @ok="addToBook()" @shown="loadBookEntries">
<ul class="list-group">
<li class="list-group-item d-flex justify-content-between align-items-center" v-for="be in this.recipe_book_list" v-bind:key="be.id">
{{ be.book_content.name }} <span class="btn btn-sm btn-danger" @click="removeFromBook(be)"><i class="fa fa-trash-alt"></i></span>
</li>
</ul>
<multiselect
style="margin-top: 1vh"
v-model="selected_book"
:options="books_filtered"
:taggable="true"
@tag="createBook"
v-bind:tag-placeholder="$t('Create')"
:placeholder="$t('Select_Book')"
label="name"
track-by="id"
id="id_books"
:multiple="false"
:loading="books_loading"
@search-change="loadBooks">
</multiselect>
</b-modal>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
import moment from 'moment'
Vue.prototype.moment = moment
import Vue from "vue";
import {BootstrapVue} from "bootstrap-vue";
import {ApiApiFactory} from "@/utils/openapi/api";
import {makeStandardToast, StandardToasts} from "@/utils/utils";
Vue.use(BootstrapVue)
export default {
name: 'AddRecipeToBook',
components: {
Multiselect
},
props: {
recipe: Object,
modal_id: Number
},
data() {
return {
books: [],
books_loading: false,
recipe_book_list: [],
selected_book: null,
}
},
computed: {
books_filtered: function () {
let books_filtered = []
this.books.forEach(b => {
if (this.recipe_book_list.filter(e => e.book === b.id).length === 0) {
books_filtered.push(b)
}
})
return books_filtered
}
},
mounted() {
},
methods: {
loadBooks: function (query) {
this.books_loading = true
let apiFactory = new ApiApiFactory()
apiFactory.listRecipeBooks({query: {query: query}}).then(results => {
this.books = results.data.filter(e => this.recipe_book_list.indexOf(e) === -1)
this.books_loading = false
})
},
createBook: function (name) {
let apiFactory = new ApiApiFactory()
apiFactory.createRecipeBook({name: name}).then(r => {
this.books.push(r.data)
this.selected_book = r.data
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE)
})
},
addToBook: function () {
let apiFactory = new ApiApiFactory()
apiFactory.createRecipeBookEntry({book: this.selected_book.id, recipe: this.recipe.id}).then(r => {
this.recipe_book_list.push(r.data)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE)
})
},
removeFromBook: function (book_entry) {
let apiFactory = new ApiApiFactory()
apiFactory.destroyRecipeBookEntry(book_entry.id).then(r => {
this.recipe_book_list = this.recipe_book_list.filter(e => e.id !== book_entry.id)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE)
})
},
loadBookEntries: function () {
let apiFactory = new ApiApiFactory()
apiFactory.listRecipeBookEntrys({query: {recipe: this.recipe.id}}).then(r => {
this.recipe_book_list = r.data
this.loadBooks('')
})
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

View File

@ -1097,6 +1097,12 @@ export interface MealPlan {
* @memberof MealPlan * @memberof MealPlan
*/ */
meal_type_name?: string; meal_type_name?: string;
/**
*
* @type {string}
* @memberof MealPlan
*/
shopping?: string;
} }
/** /**
* *
@ -3024,6 +3030,18 @@ export interface UserPreference {
* @memberof UserPreference * @memberof UserPreference
*/ */
shopping_recent_days?: number; shopping_recent_days?: number;
/**
*
* @type {string}
* @memberof UserPreference
*/
csv_delim?: string;
/**
*
* @type {string}
* @memberof UserPreference
*/
csv_prefix?: string;
} }
/** /**