Merge branch 'stable' into develop

environments/review-front-wvff-cfe5gn/deployments/13838
Marcos Peña 2022-09-12 11:37:18 +02:00
commit 875a6ba2df
13 zmienionych plików z 238 dodań i 57 usunięć

Wyświetl plik

@ -10,6 +10,65 @@ This changelog is viewable on the web at https://docs.funkwhale.audio/changelog.
.. towncrier
1.2.8 (2022-09-12)
------------------
Upgrade instructions are available at
https://docs.funkwhale.audio/admin/upgrading.html
Features:
- Add Sentry SDK to collect errors at the backend
Bugfixes:
- Fix exponentially growing database when using in-place-imports on a regular base #1676
- Fix navigating to registration request not showing anything (#1836)
- Fix player cover image overlapping queue list
- Fixed metadata handling for Various Artists albums (#1201)
- Fixed search behaviour in radio builder's filters (#733)
- Fixed unpredictable subsonic search3 results (#1782)
Committers:
- Ciarán Ainsworth
- Georg Krause
- Marcos Peña
- Mathias Koehler
- wvffle
Contributors to our Issues:
- AMoonRabbit
- Agate
- Ciarán Ainsworth
- Georg Krause
- JuniorJPDJ
- Kasper Seweryn
- Kelvin Hammond
- Marcos Peña
- Meliurwen
- Micha Gläß-Stöcker
- Miv2nir
- Sam Birch
- Tolriq
- Tony Wasserka
- f1reflyyyylmao
- heyarne
- petitminion
- troll
Contributors to our Merge Requests:
- Ciarán Ainsworth
- Georg Krause
- JuniorJPDJ
- Kasper Seweryn
- Marcos Peña
- interru
1.2.7 (2022-07-14)
------------------

Wyświetl plik

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
__version__ = "1.2.7"
__version__ = "1.2.8"
__version_info__ = tuple(
[
int(num) if num.isdigit() else num

Wyświetl plik

@ -187,7 +187,7 @@ def order_for_search(qs, field):
When searching, it's often more useful to have short results first,
this function will order the given qs based on the length of the given field
"""
return qs.annotate(__size=models.functions.Length(field)).order_by("__size")
return qs.annotate(__size=models.functions.Length(field)).order_by("__size", "pk")
def recursive_getattr(obj, key, permissive=False):

Wyświetl plik

@ -0,0 +1,35 @@
from django.core.management.base import BaseCommand
from django.db import transaction
from funkwhale_api.music import models
class Command(BaseCommand):
help = """
This command makes it easy to prune all skipped Uploads from the database.
Due to a bug they might caused the database to grow exponentially,
especially when using in-place-imports on a regular basis. This command
helps to clean up the database again.
"""
def add_arguments(self, parser):
parser.add_argument(
"--force",
default=False,
help="Disable dry run mode and apply pruning for real on the database",
)
@transaction.atomic
def handle(self, *args, **options):
skipped = models.Uploads.objects.filter(import_status="skipped")
count = len(skipped)
if options["force"]:
skipped.delete()
print(f"Deleted {count} entries from the database.")
return
print(
f"Would delete {count} entries from the database.\
Run with --force to actually apply changes to the database"
)

Wyświetl plik

@ -480,8 +480,8 @@ class ArtistField(serializers.Field):
def get_value(self, data):
if self.for_album:
keys = [
("artists", "artists"),
("names", "album_artist"),
("artists", "album_artist"),
("names", "artists"),
("mbids", "musicbrainz_albumartistid"),
]
else:
@ -525,7 +525,14 @@ class ArtistField(serializers.Field):
if separator in data["artists"]:
names = [n.strip() for n in data["artists"].split(separator)]
break
if not names:
# corner case: 'album artist' field with only one artist but multiple names in 'artits' field
if (
not names
and data.get("names", None)
and any(separator in data["names"] for separator in separators)
):
names = [n.strip() for n in data["names"].split(separators[0])]
elif not names:
names = [data["artists"]]
elif used_separator and mbids:
names = [n.strip() for n in data["names"].split(used_separator)]

Wyświetl plik

@ -284,7 +284,9 @@ def process_upload(upload, update_denormalization=True):
upload.import_status = "skipped"
upload.import_details = {
"code": "already_imported_in_owned_libraries",
"duplicates": list(owned_duplicates),
# In order to avoid exponential growth of the database, we only
# reference the first known upload which gets duplicated
"duplicates": owned_duplicates[0],
}
upload.import_date = timezone.now()
upload.save(
@ -436,6 +438,7 @@ def get_owned_duplicates(upload, track):
)
.exclude(pk=upload.pk)
.values_list("uuid", flat=True)
.order_by("creation_date")
)

Wyświetl plik

@ -2,7 +2,7 @@ import collections
import persisting_theory
from django.core.exceptions import ValidationError
from django.db.models import Q
from django.db.models import Q, functions
from django.urls import reverse_lazy
from funkwhale_api.music import models
@ -132,9 +132,13 @@ class ArtistFilter(RadioFilter):
"name": "ids",
"type": "list",
"subtype": "number",
"autocomplete": reverse_lazy("api:v1:artists-list"),
"autocomplete": reverse_lazy("api:v1:search"),
"autocomplete_qs": "q={query}",
"autocomplete_fields": {"name": "name", "value": "id"},
"autocomplete_fields": {
"remoteValues": "artists",
"name": "name",
"value": "id",
},
"label": "Artist",
"placeholder": "Select artists",
}
@ -145,7 +149,8 @@ class ArtistFilter(RadioFilter):
filter_config["ids"] = sorted(filter_config["ids"])
names = (
models.Artist.objects.filter(pk__in=filter_config["ids"])
.order_by("id")
.annotate(__size=functions.Length("name"))
.order_by("__size", "id")
.values_list("name", flat=True)
)
filter_config["names"] = list(names)
@ -176,13 +181,13 @@ class TagFilter(RadioFilter):
"name": "names",
"type": "list",
"subtype": "string",
"autocomplete": reverse_lazy("api:v1:tags-list"),
"autocomplete": reverse_lazy("api:v1:search"),
"autocomplete_fields": {
"remoteValues": "results",
"remoteValues": "tags",
"name": "name",
"value": "name",
},
"autocomplete_qs": "q={query}&ordering=length",
"autocomplete_qs": "q={query}",
"label": "Tags",
"placeholder": "Select tags",
}
@ -196,3 +201,28 @@ class TagFilter(RadioFilter):
| Q(artist__tagged_items__tag__name__in=names)
| Q(album__tagged_items__tag__name__in=names)
)
def clean_config(self, filter_config):
filter_config = super().clean_config(filter_config)
filter_config["names"] = sorted(filter_config["names"])
names = (
models.tags_models.Tag.objects.filter(name__in=filter_config["names"])
.annotate(__size=functions.Length("name"))
.order_by("__size", "pk")
.values_list("name", flat=True)
)
filter_config["names"] = list(names)
return filter_config
def validate(self, config):
super().validate(config)
try:
names = models.tags_models.Tag.objects.filter(
name__in=config["names"]
).values_list("name", flat=True)
diff = set(config["names"]) - set(names)
assert len(diff) == 0
except KeyError:
raise ValidationError("You must provide a name")
except AssertionError:
raise ValidationError('No tag matching names "{}"'.format(diff))

Wyświetl plik

@ -566,7 +566,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
except (TypeError, KeyError, ValueError):
size = 20
size = min(size, 100)
size = min(size, 500)
queryset = c["queryset"]
if query:
queryset = c["queryset"].filter(

Wyświetl plik

@ -452,7 +452,7 @@ def test_upload_import_skip_existing_track_in_own_library(factories, temp_signal
assert duplicate.import_status == "skipped"
assert duplicate.import_details == {
"code": "already_imported_in_owned_libraries",
"duplicates": [str(existing.uuid)],
"duplicates": str(existing.uuid),
}
handler.assert_called_once_with(

Wyświetl plik

@ -0,0 +1,37 @@
from funkwhale_api.radios import filters
def test_clean_config_artist_name_sorting(factories):
artist3 = factories["music.Artist"](name="The Green Eyes")
artist2 = factories["music.Artist"](name="The Green Eyed Machine")
artist1 = factories["music.Artist"](name="The Green Seed")
factories["music.Artist"]()
filter_config = {"type": "artist", "ids": [artist3.pk, artist1.pk, artist2.pk]}
artist_filter = filters.ArtistFilter()
config = artist_filter.clean_config(filter_config)
# list of names whose artists have been sorted by name then by id
sorted_names = [
a.name
for a in list(
sorted([artist2, artist1, artist3], key=lambda x: (len(x.name), x.id))
)
]
assert config["names"] == sorted_names
def test_clean_config_tag_name_sorting(factories):
tag3 = factories["tags.Tag"](name="Rock")
tag2 = factories["tags.Tag"](name="Classic")
tag1 = factories["tags.Tag"](name="Punk")
factories["tags.Tag"]()
filter_config = {"type": "tag", "names": [tag3.name, tag1.name, tag2.name]}
tag_filter = filters.TagFilter()
config = tag_filter.clean_config(filter_config)
# list of names whose tags have been sorted by name then by id
sorted_names = [
a.name
for a in list(sorted([tag2, tag1, tag3], key=lambda x: (len(x.name), x.id)))
]
assert config["names"] == sorted_names

77
docs/poetry.lock wygenerowano
Wyświetl plik

@ -15,10 +15,10 @@ optional = false
python-versions = ">=3.7"
[package.extras]
tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"]
tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
[[package]]
name = "babel"
name = "Babel"
version = "2.10.3"
description = "Internationalization utilities"
category = "main"
@ -30,7 +30,7 @@ pytz = ">=2015.7"
[[package]]
name = "certifi"
version = "2022.6.15"
version = "2022.6.15.1"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
@ -38,7 +38,7 @@ python-versions = ">=3.6"
[[package]]
name = "charset-normalizer"
version = "2.1.0"
version = "2.1.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main"
optional = false
@ -67,8 +67,8 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "django"
version = "4.0.5"
name = "Django"
version = "4.0.6"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
category = "main"
optional = false
@ -121,7 +121,7 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "jinja2"
name = "Jinja2"
version = "3.1.2"
description = "A very fast and expressive template engine."
category = "main"
@ -156,7 +156,7 @@ code_style = ["pre-commit (==2.6)"]
benchmarking = ["pytest-benchmark (>=3.2,<4.0)", "pytest", "psutil"]
[[package]]
name = "markupsafe"
name = "MarkupSafe"
version = "2.1.1"
description = "Safely add untrusted strings to HTML/XML markup."
category = "main"
@ -181,7 +181,7 @@ code_style = ["pre-commit (==2.6)"]
[[package]]
name = "mdurl"
version = "0.1.1"
version = "0.1.2"
description = "Markdown URL utilities"
category = "main"
optional = false
@ -222,13 +222,16 @@ python-versions = ">=3.6"
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
[[package]]
name = "pygments"
version = "2.12.0"
name = "Pygments"
version = "2.13.0"
description = "Pygments is a syntax highlighting package written in Python."
category = "main"
optional = false
python-versions = ">=3.6"
[package.extras]
plugins = ["importlib-metadata"]
[[package]]
name = "pyparsing"
version = "3.0.9"
@ -238,18 +241,18 @@ optional = false
python-versions = ">=3.6.8"
[package.extras]
diagrams = ["railroad-diagrams", "jinja2"]
diagrams = ["jinja2", "railroad-diagrams"]
[[package]]
name = "pytz"
version = "2022.1"
version = "2022.2.1"
description = "World timezone definitions, modern and historical"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "pyyaml"
name = "PyYAML"
version = "6.0"
description = "YAML parser and emitter for Python"
category = "main"
@ -444,7 +447,7 @@ optional = false
python-versions = ">=3.5"
[package.extras]
lint = ["flake8", "mypy", "docutils-stubs"]
lint = ["docutils-stubs", "flake8", "mypy"]
test = ["pytest"]
[[package]]
@ -465,7 +468,7 @@ python-versions = ">=3.7"
[[package]]
name = "tzdata"
version = "2022.1"
version = "2022.2"
description = "Provider of IANA time zone data"
category = "main"
optional = false
@ -477,11 +480,11 @@ version = "1.26.11"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.5.*, <4"
[package.extras]
brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"]
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[metadata]
@ -498,13 +501,13 @@ asgiref = [
{file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"},
{file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"},
]
babel = [
Babel = [
{file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"},
{file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"},
]
certifi = [
{file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"},
{file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"},
{file = "certifi-2022.6.15.1-py3-none-any.whl", hash = "sha256:43dadad18a7f168740e66944e4fa82c6611848ff9056ad910f8f7a3e46ab89e0"},
{file = "certifi-2022.6.15.1.tar.gz", hash = "sha256:cffdcd380919da6137f76633531a5817e3a9f268575c128249fb637e4f9e73fb"},
]
charset-normalizer = [
{file = "charset-normalizer-2.1.0.tar.gz", hash = "sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413"},
@ -518,9 +521,9 @@ colorama = [
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
]
django = [
{file = "Django-4.0.5-py3-none-any.whl", hash = "sha256:502ae42b6ab1b612c933fb50d5ff850facf858a4c212f76946ecd8ea5b3bf2d9"},
{file = "Django-4.0.5.tar.gz", hash = "sha256:f7431a5de7277966f3785557c3928433347d998c1e6459324501378a291e5aab"},
Django = [
{file = "Django-4.0.6-py3-none-any.whl", hash = "sha256:ca54ebedfcbc60d191391efbf02ba68fb52165b8bf6ccd6fe71f098cac1fe59e"},
{file = "Django-4.0.6.tar.gz", hash = "sha256:a67a793ff6827fd373555537dca0da293a63a316fe34cb7f367f898ccca3c3ae"},
]
django-environ = [
{file = "django-environ-0.9.0.tar.gz", hash = "sha256:bff5381533056328c9ac02f71790bd5bf1cea81b1beeb648f28b81c9e83e0a21"},
@ -538,7 +541,7 @@ imagesize = [
{file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"},
{file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
]
jinja2 = [
Jinja2 = [
{file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
]
@ -546,7 +549,7 @@ markdown-it-py = [
{file = "markdown-it-py-2.1.0.tar.gz", hash = "sha256:cf7e59fed14b5ae17c0006eff14a2d9a00ed5f3a846148153899a0224e2c07da"},
{file = "markdown_it_py-2.1.0-py3-none-any.whl", hash = "sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27"},
]
markupsafe = [
MarkupSafe = [
{file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"},
{file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"},
{file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"},
@ -593,8 +596,8 @@ mdit-py-plugins = [
{file = "mdit_py_plugins-0.3.0-py3-none-any.whl", hash = "sha256:b1279701cee2dbf50e188d3da5f51fee8d78d038cdf99be57c6b9d1aa93b4073"},
]
mdurl = [
{file = "mdurl-0.1.1-py3-none-any.whl", hash = "sha256:6a8f6804087b7128040b2fb2ebe242bdc2affaeaa034d5fc9feeed30b443651b"},
{file = "mdurl-0.1.1.tar.gz", hash = "sha256:f79c9709944df218a4cdb0fcc0b0c7ead2f44594e3e84dc566606f04ad749c20"},
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
]
myst-parser = [
{file = "myst-parser-0.18.0.tar.gz", hash = "sha256:739a4d96773a8e55a2cacd3941ce46a446ee23dcd6b37e06f73f551ad7821d86"},
@ -604,19 +607,19 @@ packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
]
pygments = [
{file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"},
{file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"},
Pygments = [
{file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"},
{file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"},
]
pyparsing = [
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
]
pytz = [
{file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"},
{file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"},
{file = "pytz-2022.2.1-py2.py3-none-any.whl", hash = "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197"},
{file = "pytz-2022.2.1.tar.gz", hash = "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5"},
]
pyyaml = [
PyYAML = [
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
@ -712,8 +715,8 @@ typing-extensions = [
{file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"},
]
tzdata = [
{file = "tzdata-2022.1-py2.py3-none-any.whl", hash = "sha256:238e70234214138ed7b4e8a0fab0e5e13872edab3be586ab8198c407620e2ab9"},
{file = "tzdata-2022.1.tar.gz", hash = "sha256:8b536a8ec63dc0751342b3984193a3118f8fca2afe25752bb9b7fffd398552d3"},
{file = "tzdata-2022.2-py2.py3-none-any.whl", hash = "sha256:c3119520447d68ef3eb8187a55a4f44fa455f30eb1b4238fa5691ba094f2b05b"},
{file = "tzdata-2022.2.tar.gz", hash = "sha256:21f4f0d7241572efa7f7a4fdabb052e61b55dc48274e6842697ccdf5253e5451"},
]
urllib3 = [
{file = "urllib3-1.26.11-py2.py3-none-any.whl", hash = "sha256:c33ccba33c819596124764c23a97d25f32b28433ba0dedeb77d873a38722c9bc"},

Wyświetl plik

@ -123,8 +123,10 @@
top: 0;
width: 32%;
> img {
height: 50vh;
width: 50vh;
width: 100%;
height: auto;
max-height: 50vh;
max-width: 50vh;
}
@include media("<desktop") {
padding: 0.5em;

Wyświetl plik

@ -233,6 +233,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56"
integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==
"@babel/helper-string-parser@^7.18.10":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56"
integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==
"@babel/helper-validator-identifier@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
@ -938,6 +943,7 @@
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600"
integrity sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==
dependencies:
"@babel/helper-string-parser" "^7.18.10"
"@babel/helper-string-parser" "^7.18.10"
"@babel/helper-validator-identifier" "^7.18.6"
to-fast-properties "^2.0.0"
@ -3499,7 +3505,7 @@ get-func-name@^2.0.0:
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==
get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.2:
get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.2, get-intrinsic@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598"
integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==
@ -3556,9 +3562,8 @@ glob-parent@^6.0.1:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.1.1"
minimatch "^5.0.1"
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^11.1.0:
version "11.12.0"