mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2025-12-24 02:39:20 -05:00
Merge branch 'develop' into feature/vue3
# Conflicts: # .gitignore # docs/contribute.md # recipes/settings.py # requirements.txt
This commit is contained in:
22
.flake8
Normal file
22
.flake8
Normal file
@@ -0,0 +1,22 @@
|
||||
[flake8]
|
||||
extend-ignore =
|
||||
# Whitespace before ':' - Required for black compatibility
|
||||
E203,
|
||||
# Line break occurred before a binary operator - Required for black compatibility
|
||||
W503,
|
||||
# Comparison to False should be 'if cond is False:' or 'if not cond:'
|
||||
E712
|
||||
exclude =
|
||||
.git,
|
||||
**/__pycache__,
|
||||
**/.git,
|
||||
**/.svn,
|
||||
**/.hg,
|
||||
**/CVS,
|
||||
**/.DS_Store,
|
||||
.vscode,
|
||||
**/*.pyc
|
||||
per-file-ignores=
|
||||
cookbook/apps.py:F401
|
||||
max-line-length = 179
|
||||
|
||||
23
.gitignore
vendored
23
.gitignore
vendored
@@ -47,6 +47,11 @@ docs/reports/**
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
mediafiles/
|
||||
*.sqlite3*
|
||||
staticfiles/
|
||||
postgresql/
|
||||
data/
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
@@ -59,24 +64,15 @@ target/
|
||||
|
||||
\.idea/dataSources\.local\.xml
|
||||
|
||||
venv/
|
||||
|
||||
mediafiles/
|
||||
|
||||
*.sqlite3*
|
||||
|
||||
\.idea/workspace\.xml
|
||||
|
||||
\.idea/misc\.xml
|
||||
|
||||
# Deployment
|
||||
|
||||
\.env
|
||||
staticfiles/
|
||||
postgresql/
|
||||
data/
|
||||
|
||||
|
||||
cookbook/static/vue
|
||||
vue/webpack-stats.json
|
||||
/docker-compose.override.yml
|
||||
vue/node_modules
|
||||
/recipes/plugins
|
||||
@@ -85,7 +81,10 @@ vetur.config.js
|
||||
cookbook/static/vue
|
||||
vue/webpack-stats.json
|
||||
cookbook/templates/sw.js
|
||||
.prettierignore
|
||||
vue/.yarn
|
||||
vue3/.vite
|
||||
|
||||
# Configs
|
||||
vetur.config.js
|
||||
venv/
|
||||
vue3/node_modules
|
||||
|
||||
13
.prettierignore
Normal file
13
.prettierignore
Normal file
@@ -0,0 +1,13 @@
|
||||
# generated files
|
||||
api.ts
|
||||
vue/src/apps/*.js
|
||||
vue/node_modules
|
||||
staticfiles/
|
||||
docs/reports/
|
||||
/vue3/src/openapi/
|
||||
|
||||
# ignored files - prettier interferes with django templates and github actions
|
||||
*.html
|
||||
*.yml
|
||||
*.yaml
|
||||
|
||||
7
.prettierrc
Normal file
7
.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"printWidth": 179,
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"experimentalTernaries": true
|
||||
}
|
||||
11
.vscode/settings.json
vendored
11
.vscode/settings.json
vendored
@@ -3,5 +3,12 @@
|
||||
"cookbook/tests"
|
||||
],
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true
|
||||
}
|
||||
"python.testing.pytestEnabled": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "eeyore.yapf",
|
||||
},
|
||||
"yapf.args": [],
|
||||
"isort.args": []
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ RUN apk add --no-cache postgresql-libs postgresql-client gettext zlib libjpeg li
|
||||
#Print all logs without buffering it.
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
ENV DOCKER true
|
||||
|
||||
#This port will be used by gunicorn.
|
||||
EXPOSE 8080
|
||||
|
||||
@@ -35,12 +33,6 @@ RUN apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev zlib-de
|
||||
#Copy project and execute it.
|
||||
COPY . ./
|
||||
|
||||
# collect the static files
|
||||
RUN /opt/recipes/venv/bin/python manage.py collectstatic_js_reverse
|
||||
RUN /opt/recipes/venv/bin/python manage.py collectstatic --noinput
|
||||
# copy the collected static files to a different location, so they can be moved into a potentially mounted volume
|
||||
RUN mv /opt/recipes/staticfiles /opt/recipes/staticfiles-collect
|
||||
|
||||
# collect information from git repositories
|
||||
RUN /opt/recipes/venv/bin/python version.py
|
||||
# delete git repositories to reduce image size
|
||||
|
||||
17
boot.sh
17
boot.sh
@@ -67,21 +67,12 @@ echo "Migrating database"
|
||||
|
||||
python manage.py migrate
|
||||
|
||||
if [[ "${DOCKER}" == "true" ]]; then
|
||||
echo "Copying cached static files from docker build"
|
||||
echo "Generating static files"
|
||||
|
||||
mkdir -p /opt/recipes/staticfiles
|
||||
rm -rf /opt/recipes/staticfiles/*
|
||||
mv /opt/recipes/staticfiles-collect/* /opt/recipes/staticfiles
|
||||
rm -rf /opt/recipes/staticfiles-collect
|
||||
else
|
||||
echo "Collecting static files, this may take a while..."
|
||||
python manage.py collectstatic_js_reverse
|
||||
python manage.py collectstatic --noinput
|
||||
|
||||
python manage.py collectstatic_js_reverse
|
||||
python manage.py collectstatic --noinput
|
||||
|
||||
echo "Done"
|
||||
fi
|
||||
echo "Done"
|
||||
|
||||
chmod -R 755 /opt/recipes/mediafiles
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ class StepAdmin(admin.ModelAdmin):
|
||||
@admin.display(description="Name")
|
||||
def recipe_and_name(obj):
|
||||
if not obj.recipe_set.exists():
|
||||
return f"Orphaned Step{'':s if not obj.name else f': {obj.name}'}"
|
||||
return f"Orphaned Step{'' if not obj.name else f': {obj.name}'}"
|
||||
return f"{obj.recipe_set.first().name}: {obj.name}" if obj.name else obj.recipe_set.first().name
|
||||
|
||||
|
||||
@@ -376,10 +376,17 @@ class ShareLinkAdmin(admin.ModelAdmin):
|
||||
admin.site.register(ShareLink, ShareLinkAdmin)
|
||||
|
||||
|
||||
@admin.action(description='Delete all properties with type')
|
||||
def delete_properties_with_type(modeladmin, request, queryset):
|
||||
for pt in queryset:
|
||||
Property.objects.filter(property_type=pt).delete()
|
||||
|
||||
|
||||
class PropertyTypeAdmin(admin.ModelAdmin):
|
||||
search_fields = ('space',)
|
||||
search_fields = ('name',)
|
||||
|
||||
list_display = ('id', 'space', 'name', 'fdc_id')
|
||||
actions = [delete_properties_with_type]
|
||||
|
||||
|
||||
admin.site.register(PropertyType, PropertyTypeAdmin)
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
If you like this application and want it to improve, feel free to contribute to its development.
|
||||
|
||||
!!! success "Contribution List"
|
||||
If you help bring this project forward you deserve to be credited for it.
|
||||
Feel free to add yourself to `CONTRIBUTERS.md` or message me to add you if you have contributed anything.
|
||||
|
||||
## Issues
|
||||
The most basic but also very important way of contributing is reporting issues and commenting on ideas and feature requests
|
||||
over at [GitHub issues](https://github.com/vabene1111/recipes/issues).
|
||||
|
||||
Without feedback improvement can't happen, so don't hesitate to say what you want to say.
|
||||
|
||||
## Contributing Code
|
||||
If you want to contribute bug fixes or small tweaks then your pull requests are always welcome!
|
||||
|
||||
!!! danger "Discuss First!"
|
||||
If you want to contribute larger features that introduce more complexity to the project please
|
||||
make sure to **first submit a technical description** outlining what and how you want to do it.
|
||||
This allows me and the community to give feedback and manage the complexity of the overall
|
||||
application. If you don't do this please don't be mad if I reject your PR
|
||||
|
||||
!!! info
|
||||
The dev setup is a little messy as this application combines the best (at least in my opinion) of both Django and Vue.js.
|
||||
|
||||
### Devcontainer Setup
|
||||
There is a [devcontainer](https://containers.dev) set up to ease development. It is optimized for VSCode, but should be able to
|
||||
be used by other editors as well. Once the container is running, you can do things like start a Django dev server, start a Vue.js
|
||||
dev server, run python tests, etc. by either using the VSCode tasks below, or manually running commands described in the individual
|
||||
technology sections below.
|
||||
|
||||
In VSCode, simply check out the git repository, and then via the command palette, choose `Dev Containers: Reopen in container`.
|
||||
|
||||
If you need to change python dependencies (requierments.txt) or OS packages, you will need to rebuild the container. If you are
|
||||
changing OS package requirements, you will need to update both the main `Dockerfile` and the `.devcontainer/Dockerfile`.
|
||||
|
||||
### VSCode Tasks
|
||||
If you use VSCode, there are a number of tasks that are available. Here are a few of the key ones:
|
||||
|
||||
* `Setup Dev Server` - Runs all the prerequisite steps so that the dev server can be run inside VSCode.
|
||||
* `Setup Tests` - Runs all prerequisites so tests can be run inside VSCode.
|
||||
|
||||
Once these are run, you should be able to run/debug a django server in VSCode as well as run/debug tests directly through VSCode.
|
||||
There are also a few other tasks specified in case you have specific development needs:
|
||||
|
||||
* `Run Dev Server` - Runs a django development server not connected to VSCode.
|
||||
* `Run all pytests` - Runs all the pytests outside of VSCode.
|
||||
* `Yarn Serve` - Runs development Vue.js server not connected to VSCode. Useful if you want to make Vue changes and see them in realtime.
|
||||
* `Serve Documentation` - Runs a documentation server. Useful if you want to see how changes to documentation show up.
|
||||
|
||||
### Django
|
||||
This application is developed using the Django framework for Python. They have excellent
|
||||
[documentation](https://www.djangoproject.com/start/) on how to get started, so I will only give you the basics here.
|
||||
|
||||
1. Clone this repository wherever you like and install the Python language for your OS (I recommend using version 3.10 or above).
|
||||
2. Open it in your favorite editor/IDE (e.g. PyCharm).
|
||||
a. If you want, create a virtual environment for all your packages.
|
||||
3. Install all required packages: `pip install -r requirements.txt`.
|
||||
4. Run the migrations: `python manage.py migrate`.
|
||||
5. Start the development server: `python manage.py runserver`.
|
||||
|
||||
There is **no** need to set any environment variables. By default, a simple SQLite database is used and all settings are
|
||||
populated from default values.
|
||||
|
||||
### Vue.js
|
||||
Most new frontend pages are build using [Vue.js](https://vuejs.org/).
|
||||
|
||||
In order to work on these pages, you will have to install a Javascript package manager of your choice. The following examples use yarn.
|
||||
|
||||
In the `vue3` folder run `yarn install` to install the dependencies. After that you can use `yarn serve` to start the development server,
|
||||
and proceed to test your changes. If you do not wish to work on those pages, but instead want the application to work properly during
|
||||
development, run `yarn build` to build the frontend pages once.
|
||||
|
||||
#### API Client
|
||||
The API Client is generated automatically from the OpenAPI interface provided by the Django REST framework.
|
||||
For this [openapi-generator](https://github.com/OpenAPITools/openapi-generator) is used.
|
||||
|
||||
Install it using your desired setup method. (For example, using `npm install @openapitools/openapi-generator-cli -g`.)
|
||||
|
||||
Navigate to `vue3/src/openapi`.
|
||||
|
||||
Generate the schema using `openapi-generator-cli generate -g typescript-fetch -i http://127.0.0.1:8000/openapi/`. (Replace your dev server url if required.)
|
||||
|
||||
## Contribute Documentation
|
||||
The documentation is built from the markdown files in the [docs](https://github.com/vabene1111/recipes/tree/develop/docs)
|
||||
folder of the GitHub repository.
|
||||
|
||||
In order to contribute to the documentation, you can fork the repository and edit the markdown files in the browser.
|
||||
|
||||
Now install mkdocs and dependencies: `pip install mkdocs-material mkdocs-include-markdown-plugin`.
|
||||
|
||||
If you want to test the documentation, locally run `mkdocs serve` from the project root.
|
||||
|
||||
## Contribute Translations
|
||||
|
||||
If you know any foreign languages that the project has not been completely translated to yet, feel free to contribute translations.
|
||||
|
||||
Translations are managed on [translate.tandoor.dev](https://translate.tandoor.dev/), a self hosted instance of [Weblate](https://weblate.org/de/).
|
||||
|
||||
You can simply register an account and then follow these steps to add translations:
|
||||
|
||||
1. After registering, you are asked to select your languages. This is optional but allows weblate to only show you relevant translations.
|
||||
2. In the navigation click on `Projects` and then `Browse all projects`.
|
||||
3. Select Tandoor and on the top-right hand corner, select `Watch project Tandoor` (click on `Not watching`).
|
||||
4. Go back to the dashboard. It now shows you the relevant translations for your languages. Click on the pencil icon to get started.
|
||||
|
||||
!!! info "Creating a new language"
|
||||
To create a new language you must first select Tandoor (the project) and then a component.
|
||||
Here you will have the option to add the language. Afterwards you can also simply add it to the other components as well.
|
||||
Once a new language is (partially) finished let me know on GitHub so I can add it to the language-switcher in Tandoor itself.
|
||||
|
||||
There is also [a lot of documentation](https://docs.weblate.org/en/latest/user/translating.html) available from Weblate directly.
|
||||
|
||||

|
||||
|
||||
It is also possible to provide the translations directly by creating a new language
|
||||
using `manage.py makemessages -l <language_code> -i venv`. Once finished, simply open a PR with the changed files. This sometimes causes issues merging
|
||||
with weblate, so I would prefer the use of weblate.
|
||||
BIN
docs/contribute/assets/flake8_watcher.png
Normal file
BIN
docs/contribute/assets/flake8_watcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
BIN
docs/contribute/assets/isort_watcher.png
Normal file
BIN
docs/contribute/assets/isort_watcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
docs/contribute/assets/linting_error.png
Normal file
BIN
docs/contribute/assets/linting_error.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/contribute/assets/prettier_watcher.png
Normal file
BIN
docs/contribute/assets/prettier_watcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
BIN
docs/contribute/assets/yapf_watcher.png
Normal file
BIN
docs/contribute/assets/yapf_watcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
55
docs/contribute/contribute.md
Normal file
55
docs/contribute/contribute.md
Normal file
@@ -0,0 +1,55 @@
|
||||
If you like this application and want it to give back, there are many ways to contribute.
|
||||
|
||||
!!! success "Contribution List"
|
||||
If you help bring this project forward you deserve to be credited for it.
|
||||
Feel free to add yourself to `CONTRIBUTERS.md` or message me to add you if you have contributed anything.
|
||||
|
||||
## Translations
|
||||
|
||||
If you know any foreign languages you can:
|
||||
Improve the translations for any of the existing languages.
|
||||
|
||||
Add a new language to the long list of existing translations.
|
||||
|
||||
- Armenian
|
||||
- Bulgarian
|
||||
- Catalan
|
||||
- Czech
|
||||
- Danish
|
||||
- Dutch
|
||||
- English
|
||||
- French
|
||||
- German
|
||||
- Hungarian
|
||||
- Italian
|
||||
- Latvian
|
||||
- Norwegian
|
||||
- Polish
|
||||
- Russian
|
||||
- Spanish
|
||||
- Swedish
|
||||
|
||||
See [here](/contribute/translations) for further information on how to contribute translation to Tandoor.
|
||||
|
||||
## Issues and Feature Requests
|
||||
|
||||
The most basic but also very important way of contributing is reporting issues and commenting on ideas and feature requests
|
||||
over at [GitHub issues](https://github.com/vabene1111/recipes/issues).
|
||||
|
||||
Without feedback improvement can't happen, so don't hesitate to say what you want to say.
|
||||
|
||||
## Documentation
|
||||
|
||||
Helping improve the documentation for Tandoor is one of the easiest ways to give back and doesn't even require deep technical knowledge.
|
||||
You can write guides on how to install and configure Tandoor expanding our repository of non-standard configuations.
|
||||
Or you can write how-to guides using some of Tandoor's advanced features such as authentication or automation.
|
||||
|
||||
See [here](/contribute/documentation) for more information on how to add documentation to Tandoor.
|
||||
|
||||
## Contributing Code
|
||||
|
||||
For the truly ambitious, you can help write code to fix issues, add additional features, or write your own scripts using
|
||||
Tandoor's extensive API and share your work with the community.
|
||||
|
||||
Before writing any code, please make sure that you review [contribution guidelines](/contribute/guidelines) and
|
||||
[VSCode](/contribute/vscode) or [PyCharm](/contribute/pycharm) specific configurations.
|
||||
26
docs/contribute/documentation.md
Normal file
26
docs/contribute/documentation.md
Normal file
@@ -0,0 +1,26 @@
|
||||
The documentation is built from the markdown files in the [docs](https://github.com/vabene1111/recipes/tree/develop/docs)
|
||||
folder of the GitHub repository.
|
||||
|
||||
In order to contribute to the documentation, there are a couple of methods that you can use.
|
||||
|
||||
## Directly on GitHub
|
||||
|
||||
You can fork the develop repository and edit the markdown files directly on the GitHub website.
|
||||
|
||||
## With an IDE
|
||||
|
||||
You can fork the develop repository and edit the markdown files from your favorite IDE such as VSCode or PyCharm.
|
||||
One advantage of using as IDE is that you can preview your changes by:
|
||||
|
||||
### Installing mkdocs
|
||||
|
||||
Now install mkdocs and dependencies: `pip install mkdocs-material mkdocs-include-markdown-plugin`.
|
||||
|
||||
### Serving Documetation
|
||||
|
||||
If you want to test the documentation, locally run `mkdocs serve` from the project root.
|
||||
|
||||
## Super Low Tech
|
||||
|
||||
Create your documentation in any work processor (or even create a video!) and [open a feature request](https://github.com/vabene1111/recipes/issues)
|
||||
attaching your document and requesting that someone add the documentation to Tandoor.
|
||||
63
docs/contribute/guidelines.md
Normal file
63
docs/contribute/guidelines.md
Normal file
@@ -0,0 +1,63 @@
|
||||
If you want to contribute bug fixes or small tweaks then your pull requests are always welcome!
|
||||
|
||||
!!! danger "Discuss First!"
|
||||
If you want to contribute larger features that introduce more complexity to the project please
|
||||
make sure to **first submit a technical description** outlining what and how you want to do it.
|
||||
This allows me and the community to give feedback and manage the complexity of the overall
|
||||
application. If you don't do this please don't be mad if I reject your PR.
|
||||
|
||||
## License
|
||||
|
||||
Contributing to Tandoor requires signing a Contributor License Agreement. You can review the CLA [here](https://cla-assistant.io/TandoorRecipes/recipes).
|
||||
|
||||
## Linting & Formatting
|
||||
|
||||
Tandoor uses a number of libraries to maintain style and formatting consistency.
|
||||
To contribute to the project you are required to use the following packages with the project defined configurations:
|
||||
|
||||
- flake8
|
||||
- yapf
|
||||
- isort
|
||||
- prettier
|
||||
|
||||
!!! tip "Manual Formatting"
|
||||
It is possible to run formatting manually, but it is recommended to setup your IDE to format on save.
|
||||
``` bash
|
||||
flake8 file.py --ignore=E501 | isort -q file.py | yapf -i file.py
|
||||
prettier --write file.vue
|
||||
```
|
||||
|
||||
## Testing
|
||||
Django uses pytest-django to implement a full suite of testing. If you make any functional changes, please implment the appropriate
|
||||
tests.
|
||||
|
||||
Tandoor is also actively soliciting contribors willing to setup vue3 testing. If you have knowledge in this area it would be greatly appreciated.
|
||||
|
||||
## API Client
|
||||
|
||||
Tandoor uses [django-rest-framework](https://www.django-rest-framework.org/) for API implementation. Making contributions that impact the API requires an understanding of
|
||||
Viewsets and Serializers.
|
||||
|
||||
Also double check that your changes are actively reflected in the schema so that client apis are generated accurately.
|
||||
|
||||
The API Client is generated automatically from the OpenAPI interface provided by the Django REST framework.
|
||||
For this [openapi-generator](https://github.com/OpenAPITools/openapi-generator) is used.
|
||||
|
||||
Install it using your desired setup method. (For example, using `npm install @openapitools/openapi-generator-cli -g`.)
|
||||
|
||||
### Vue
|
||||
|
||||
Navigate to `vue/src/utils/openapi`.
|
||||
|
||||
Generate the schema using `openapi-generator-cli generate -g typescript-axios -i http://127.0.0.1:8000/openapi/`. (Replace your dev server url if required.)
|
||||
|
||||
### Vue3
|
||||
|
||||
Navigate to `vue3/src/openapi`.
|
||||
|
||||
Generate the schema using `openapi-generator-cli generate -g typescript-fetch -i http://127.0.0.1:8000/openapi/`. (Replace your dev server url if required.)
|
||||
|
||||
## Install and Configuration
|
||||
|
||||
Instructions for [VSCode](/contribute/vscode)
|
||||
Instructions for [PyCharm](/contribute/pycharm)
|
||||
39
docs/contribute/installation.md
Normal file
39
docs/contribute/installation.md
Normal file
@@ -0,0 +1,39 @@
|
||||
!!! info
|
||||
The dev setup is a little messy as this application combines the best (at least in my opinion) of both Django and Vue.js.
|
||||
|
||||
### Devcontainer Setup
|
||||
|
||||
There is a [devcontainer](https://containers.dev) set up to ease development. It is optimized for VSCode, but should be able to
|
||||
be used by other editors as well. Once the container is running, you can do things like start a Django dev server, start a Vue.js
|
||||
dev server, run python tests, etc. by either using the VSCode tasks below, or manually running commands described in the individual
|
||||
technology sections below.
|
||||
|
||||
In VSCode, simply check out the git repository, and then via the command palette, choose `Dev Containers: Reopen in container`.
|
||||
|
||||
If you need to change python dependencies (requierments.txt) or OS packages, you will need to rebuild the container. If you are
|
||||
changing OS package requirements, you will need to update both the main `Dockerfile` and the `.devcontainer/Dockerfile`.
|
||||
|
||||
### Django
|
||||
|
||||
This application is developed using the Django framework for Python. They have excellent
|
||||
[documentation](https://www.djangoproject.com/start/) on how to get started, so I will only give you the basics here.
|
||||
|
||||
1. Clone this repository wherever you like and install the Python language for your OS (I recommend using version 3.10 or above).
|
||||
2. Open it in your favorite editor/IDE (e.g. PyCharm).
|
||||
a. If you want, create a virtual environment for all your packages.
|
||||
3. Install all required packages: `pip install -r requirements.txt`.
|
||||
4. Run the migrations: `python manage.py migrate`.
|
||||
5. Start the development server: `python manage.py runserver`.
|
||||
|
||||
There is **no** need to set any environment variables. By default, a simple SQLite database is used and all settings are
|
||||
populated from default values.
|
||||
|
||||
### Vue.js
|
||||
|
||||
Most new frontend pages are build using [Vue.js](https://vuejs.org/).
|
||||
|
||||
In order to work on these pages, you will have to install a Javascript package manager of your choice. The following examples use yarn.
|
||||
|
||||
In the `vue` folder run `yarn install` to install the dependencies. After that you can use `yarn serve` to start the development server,
|
||||
and proceed to test your changes. If you do not wish to work on those pages, but instead want the application to work properly during
|
||||
development, run `yarn build` to build the frontend pages once.
|
||||
62
docs/contribute/pycharm.md
Normal file
62
docs/contribute/pycharm.md
Normal file
@@ -0,0 +1,62 @@
|
||||
PyCharm can be configured to format and lint on save. Doing so requires some manual configuration as outlined below.
|
||||
|
||||
## Setup File Watchers
|
||||
|
||||
1. Navigate to File -> Settings -> Plugins
|
||||
2. Download and install [File Watchers](https://plugins.jetbrains.com/plugin/7177-file-watchers)
|
||||
3. Navigate to File -> Settings -> Tools -> Black
|
||||
4. Confirm 'Use Black Formatter' is unchecked for both 'On code reformat' and 'On save'
|
||||
|
||||
## Setup flake8 Watcher
|
||||
|
||||
1. Navigate to File -> Settings -> Tools -> File Watchers
|
||||
2. Click the '+' to add a new watcher.
|
||||
3. Configure the watcher as below.
|
||||
|
||||

|
||||
|
||||
4. Navigate to File -> Settings -> Editor -> Inspections -> File watcher problems
|
||||
5. Under Severity select 'Edit Severities'
|
||||
6. Click the '+' to add a severity calling it 'Linting Error'
|
||||
7. Configure a background and effect as below.
|
||||
|
||||

|
||||
|
||||
## Setup isort
|
||||
|
||||
1. Navigate to File -> Settings -> Tools -> File Watchers
|
||||
2. Click the '+' to add a new watcher.
|
||||
3. Configure the watcher as below.
|
||||
|
||||

|
||||
|
||||
## Setup yapf
|
||||
|
||||
1. Navigate to File -> Settings -> Tools -> File Watchers
|
||||
2. Click the '+' to add a new watcher.
|
||||
3. Configure the watcher as below.
|
||||
|
||||

|
||||
|
||||
<!-- prettier-ignore -->
|
||||
!!! hint
|
||||
Adding a comma at the end of a list will trigger yapf to put each element of the list on a new line
|
||||
|
||||
## Setup prettier
|
||||
|
||||
1. Navigate to File -> Settings -> Tools -> File Watchers
|
||||
2. Click the '+' to add a new watcher.
|
||||
3. Change 'File Type' to 'Any'.
|
||||
4. Click the three dots next to 'Scope' to create a custom scope.
|
||||
5. Click '+' to add a new scope
|
||||
|
||||
- Name: prettier
|
||||
- Pattern: `file:vue/src//*||file:vue3/src//*||file:docs//*`
|
||||
|
||||
6. Configure the watcher as below.
|
||||
|
||||

|
||||
|
||||
- Arguments: `--cwd $ProjectFileDir$\vue prettier -w --config $ProjectFileDir$\.prettierrc $FilePath$`
|
||||
|
||||
## Setup Volar??
|
||||
25
docs/contribute/related.md
Normal file
25
docs/contribute/related.md
Normal file
@@ -0,0 +1,25 @@
|
||||
## Recipe Scraper
|
||||
|
||||
While not directly related to Tandoor, we make extensive use of the brilliant [recipe-scrapers](https://github.com/hhursev/recipe-scrapers)
|
||||
package by hhursev.
|
||||
|
||||
If you have the skills to add new sites or help resolve issues you are indirectly helping Tandoor.
|
||||
|
||||
## Unofficial mobile app
|
||||
|
||||
Maintained by [phantomate](https://github.com/phantomate/Untare)
|
||||
|
||||
[iPhone](https://apps.apple.com/nl/app/untare/id6448643329?l=en&platform=iphone)
|
||||
[Android](https://play.google.com/store/apps/details?id=unofficial.tandoor.recipes)
|
||||
|
||||
## GPT Recipe
|
||||
|
||||
Maintained by [John Pedrie](https://github.com/jdpedrie/gpt-recipe)
|
||||
|
||||
Convert pictures of recipes to a structure that can be imported to Tandoor with ChatGPT.
|
||||
|
||||
## Tandoor Menu Generator
|
||||
|
||||
Maintained by [smilerz](https://github.com/smilerz/tandoor-menu-generator)
|
||||
|
||||
Generate a mealplan tbased on complex criteria and optionally insert it into an SVG menu template.
|
||||
21
docs/contribute/translations.md
Normal file
21
docs/contribute/translations.md
Normal file
@@ -0,0 +1,21 @@
|
||||
Translations are managed on [translate.tandoor.dev](https://translate.tandoor.dev/), a self hosted instance of [Weblate](https://weblate.org/de/).
|
||||
|
||||
You can simply register an account and then follow these steps to add translations:
|
||||
|
||||
1. After registering, you are asked to select your languages. This is optional but allows weblate to only show you relevant translations.
|
||||
2. In the navigation click on `Projects` and then `Browse all projects`.
|
||||
3. Select Tandoor and on the top-right hand corner, select `Watch project Tandoor` (click on `Not watching`).
|
||||
4. Go back to the dashboard. It now shows you the relevant translations for your languages. Click on the pencil icon to get started.
|
||||
|
||||
!!! info "Creating a new language"
|
||||
To create a new language you must first select Tandoor (the project) and then a component.
|
||||
Here you will have the option to add the language. Afterwards you can also simply add it to the other components as well.
|
||||
Once a new language is (partially) finished let me know on GitHub so I can add it to the language-switcher in Tandoor itself.
|
||||
|
||||
There is also [a lot of documentation](https://docs.weblate.org/en/latest/user/translating.html) available from Weblate directly.
|
||||
|
||||

|
||||
|
||||
It is also possible to provide the translations directly by creating a new language
|
||||
using `manage.py makemessages -l <language_code> -i venv`. Once finished, simply open a PR with the changed files. This sometimes causes issues merging
|
||||
with weblate, so I would prefer the use of weblate.
|
||||
45
docs/contribute/vscode.md
Normal file
45
docs/contribute/vscode.md
Normal file
@@ -0,0 +1,45 @@
|
||||
Configurations for debugging django, volar, testing, linting and formatting are all include in the project files.
|
||||
|
||||
## Extensions
|
||||
|
||||
VSCode can be configured to format and lint on save instead of manually formatting files before submitting a pull request.
|
||||
To enable auto-formatting and linting install the following extensions in VSCode:
|
||||
|
||||
Name: Flake8
|
||||
Publisher: Microsoft
|
||||
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=ms-python.flake8
|
||||
|
||||
Name: yapf
|
||||
Publisher: EeyoreLee
|
||||
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=eeyore.yapf
|
||||
|
||||
Name: isort
|
||||
Publisher: Microsoft
|
||||
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=ms-python.isort
|
||||
|
||||
Name: Vue - Official
|
||||
Publisher: Vue
|
||||
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=Vue.volar
|
||||
|
||||
Name: Prettier - Code formatter
|
||||
Publisher: Prettier
|
||||
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
!!! hint
|
||||
Adding a comma at the end of a list will trigger yapf to put each element of the list on a new line
|
||||
|
||||
## VSCode Tasks
|
||||
|
||||
There are a number of built in tasks that are available. Here are a few of the key ones:
|
||||
|
||||
- `Setup Dev Server` - Runs all the prerequisite steps so that the dev server can be run inside VSCode.
|
||||
- `Setup Tests` - Runs all prerequisites so tests can be run inside VSCode.
|
||||
|
||||
Once these are run, you should be able to run/debug a django server in VSCode as well as run/debug tests directly through VSCode.
|
||||
There are also a few other tasks specified in case you have specific development needs:
|
||||
|
||||
- `Run Dev Server` - Runs a django development server not connected to VSCode.
|
||||
- `Run all pytests` - Runs all the pytests outside of VSCode.
|
||||
- `Yarn Serve` - Runs development Vue.js server not connected to VSCode. Useful if you want to make Vue changes and see them in realtime.
|
||||
- `Serve Documentation` - Runs a documentation server. Useful if you want to see how changes to documentation show up.
|
||||
@@ -1,27 +0,0 @@
|
||||
Following is a description of the different settings for a space
|
||||
|
||||
!!! WARNING WIP
|
||||
Some settings and especially this page is work in Progress and the settings may
|
||||
behave differently the described here.
|
||||
|
||||
## Use Plural form
|
||||
|
||||
Default Value: `off`
|
||||
|
||||
This setting enables tandoor to display a plural form of a food or unit, if the
|
||||
plural version is entered for the food or unit. The plural version is displayed if the
|
||||
amount needed for a recipe is greater than 1 and will be adjusted to the current amount.
|
||||
|
||||
In addition, this setting enables two new settings for an ingredient:
|
||||
|
||||
- Always show the plural version of the food: This will always display the plural version for
|
||||
a food, even if the amount is below or equal to 1. Requirement for this setting to activate
|
||||
is a plural version available in the database.
|
||||
- Always show the plural version of the unit: This will always display the plural version for
|
||||
a unit, even if the amount is below or equal to 1. Requirement for this setting to activate
|
||||
is a plural version available in the database.
|
||||
|
||||
!!! WARNING Note
|
||||
This setting is only meant to be a very simple version to enable some kind of pluralization
|
||||
for food and units. This feature may not meet your needs, but pluralization is a difficult
|
||||
topic and was discussed [here](https://github.com/TandoorRecipes/recipes/pull/1860).
|
||||
14
mkdocs.yml
14
mkdocs.yml
@@ -36,6 +36,7 @@ nav:
|
||||
- TrueNAS Portainer: install/truenas_portainer.md
|
||||
- WSL: install/wsl.md
|
||||
- ArchLinux: install/archlinux.md
|
||||
- HomeAssistant: install/homeassistant.md
|
||||
- Manual: install/manual.md
|
||||
- Other setups: install/other.md
|
||||
- Features:
|
||||
@@ -46,10 +47,21 @@ nav:
|
||||
- Connectors: features/connectors.md
|
||||
- Storages and Sync: features/external_recipes.md
|
||||
- Import/Export: features/import_export.md
|
||||
- Telegram bot: features/telegram_bot.md
|
||||
- System:
|
||||
- Configuration: system/configuration.md
|
||||
- Updating: system/updating.md
|
||||
- Migrate sqlite to postgres: system/migration_sqlite-postgres.md
|
||||
- Permission System: system/permissions.md
|
||||
- Backup: system/backup.md
|
||||
- Contributing: contribute.md
|
||||
- Contributing:
|
||||
- Overview: contribute/contribute.md
|
||||
- Translations: contribute/translations.md
|
||||
- Documentation: contribute/documentation.md
|
||||
- Code: contribute/guidelines.md
|
||||
- Installation: contribute/installation.md
|
||||
- IDE Setup:
|
||||
- VSCode: contribute/vscode.md
|
||||
- PyCharm: contribute/pycharm.md
|
||||
- Related Projects: contribute/related.md
|
||||
- FAQ: faq.md
|
||||
|
||||
12
pyproject.toml
Normal file
12
pyproject.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[tool.yapf]
|
||||
column_limit = 179
|
||||
based_on_style = "pep8"
|
||||
DISABLE_ENDING_COMMA_HEURISTIC = false
|
||||
COALESCE_BRACKETS = true
|
||||
DEDENT_CLOSING_BRACKETS = true
|
||||
FORCE_MULTILINE_DICT = false
|
||||
|
||||
[tool.isort]
|
||||
multi_line_output = 5
|
||||
skip = [".gitignore", ".dockerignore"]
|
||||
line_length = 179
|
||||
@@ -210,10 +210,18 @@ ENABLE_PDF_EXPORT = bool(int(os.getenv('ENABLE_PDF_EXPORT', False)))
|
||||
EXPORT_FILE_CACHE_DURATION = int(os.getenv('EXPORT_FILE_CACHE_DURATION', 600))
|
||||
|
||||
MIDDLEWARE = [
|
||||
'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'cookbook.helper.scope_middleware.ScopeMiddleware', 'allauth.account.middleware.AccountMiddleware',
|
||||
'corsheaders.middleware.CorsMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'cookbook.helper.scope_middleware.ScopeMiddleware',
|
||||
'allauth.account.middleware.AccountMiddleware',
|
||||
]
|
||||
|
||||
if DEBUG_TOOLBAR:
|
||||
@@ -244,7 +252,11 @@ if LDAP_AUTH:
|
||||
AUTH_LDAP_START_TLS = bool(int(os.getenv('AUTH_LDAP_START_TLS', False)))
|
||||
AUTH_LDAP_BIND_DN = os.getenv('AUTH_LDAP_BIND_DN')
|
||||
AUTH_LDAP_BIND_PASSWORD = os.getenv('AUTH_LDAP_BIND_PASSWORD')
|
||||
AUTH_LDAP_USER_SEARCH = LDAPSearch(os.getenv('AUTH_LDAP_USER_SEARCH_BASE_DN'), ldap.SCOPE_SUBTREE, os.getenv('AUTH_LDAP_USER_SEARCH_FILTER_STR', '(uid=%(user)s)'), )
|
||||
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
||||
os.getenv('AUTH_LDAP_USER_SEARCH_BASE_DN'),
|
||||
ldap.SCOPE_SUBTREE,
|
||||
os.getenv('AUTH_LDAP_USER_SEARCH_FILTER_STR', '(uid=%(user)s)'),
|
||||
)
|
||||
AUTH_LDAP_USER_ATTR_MAP = ast.literal_eval(os.getenv('AUTH_LDAP_USER_ATTR_MAP')) if os.getenv('AUTH_LDAP_USER_ATTR_MAP') else {
|
||||
'first_name': 'givenName',
|
||||
'last_name': 'sn',
|
||||
@@ -271,7 +283,10 @@ if LDAP_AUTH:
|
||||
},
|
||||
}
|
||||
|
||||
AUTHENTICATION_BACKENDS += ['django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend', ]
|
||||
AUTHENTICATION_BACKENDS += [
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'allauth.account.auth_backends.AuthenticationBackend',
|
||||
]
|
||||
|
||||
# django allauth site id
|
||||
SITE_ID = int(os.getenv('ALLAUTH_SITE_ID', 1))
|
||||
@@ -285,15 +300,20 @@ if REMOTE_USER_AUTH:
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
}, {
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
}, {
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
}, {
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
}, ]
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
|
||||
@@ -358,17 +378,23 @@ SPECTACULAR_SETTINGS = {
|
||||
|
||||
ROOT_URLCONF = 'recipes.urls'
|
||||
|
||||
TEMPLATES = [{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'cookbook', 'templates')],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages', 'django.template.context_processors.media', 'cookbook.helper.context_processors.context_settings',
|
||||
],
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'cookbook', 'templates')],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django.template.context_processors.media',
|
||||
'cookbook.helper.context_processors.context_settings',
|
||||
],
|
||||
},
|
||||
},
|
||||
}, ]
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'recipes.wsgi.application'
|
||||
|
||||
@@ -439,7 +465,12 @@ def setup_database(db_url=None, db_options=None, db_engine=None, pg_host=None, p
|
||||
|
||||
DATABASES = setup_database()
|
||||
|
||||
CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'default', }}
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||
'LOCATION': 'default',
|
||||
}
|
||||
}
|
||||
|
||||
# Vue webpack settings
|
||||
VUE_DIR = os.path.join(BASE_DIR, 'vue')
|
||||
@@ -502,9 +533,25 @@ USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
LANGUAGES = [('hy', _('Armenian ')), ('bg', _('Bulgarian')), ('ca', _('Catalan')), ('cs', _('Czech')), ('da', _('Danish')), ('nl', _('Dutch')), ('en', _('English')),
|
||||
('fr', _('French')), ('de', _('German')), ('hu', _('Hungarian')), ('it', _('Italian')), ('lv', _('Latvian')), ('nb', _('Norwegian ')), ('pl', _('Polish')),
|
||||
('ru', _('Russian')), ('es', _('Spanish')), ('sv', _('Swedish')), ]
|
||||
LANGUAGES = [
|
||||
('hy', _('Armenian ')),
|
||||
('bg', _('Bulgarian')),
|
||||
('ca', _('Catalan')),
|
||||
('cs', _('Czech')),
|
||||
('da', _('Danish')),
|
||||
('nl', _('Dutch')),
|
||||
('en', _('English')),
|
||||
('fr', _('French')),
|
||||
('de', _('German')),
|
||||
('hu', _('Hungarian')),
|
||||
('it', _('Italian')),
|
||||
('lv', _('Latvian')),
|
||||
('nb', _('Norwegian ')),
|
||||
('pl', _('Polish')),
|
||||
('ru', _('Russian')),
|
||||
('es', _('Spanish')),
|
||||
('sv', _('Swedish')),
|
||||
]
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/2.0/howto/static-files/
|
||||
@@ -562,7 +609,13 @@ ACCOUNT_EMAIL_SUBJECT_PREFIX = os.getenv('ACCOUNT_EMAIL_SUBJECT_PREFIX', '[Tando
|
||||
ACCOUNT_FORMS = {'signup': 'cookbook.forms.AllAuthSignupForm', 'reset_password': 'cookbook.forms.CustomPasswordResetForm'}
|
||||
|
||||
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False
|
||||
ACCOUNT_RATE_LIMITS = {"change_password": "1/m/user", "reset_password": "1/m/ip,1/m/key", "reset_password_from_key": "1/m/ip", "signup": "5/m/ip", "login": "5/m/ip", }
|
||||
ACCOUNT_RATE_LIMITS = {
|
||||
"change_password": "1/m/user",
|
||||
"reset_password": "1/m/ip,1/m/key",
|
||||
"reset_password_from_key": "1/m/ip",
|
||||
"signup": "5/m/ip",
|
||||
"login": "5/m/ip",
|
||||
}
|
||||
|
||||
DISABLE_EXTERNAL_CONNECTORS = bool(int(os.getenv('DISABLE_EXTERNAL_CONNECTORS', False)))
|
||||
EXTERNAL_CONNECTORS_QUEUE_SIZE = int(os.getenv('EXTERNAL_CONNECTORS_QUEUE_SIZE', 100))
|
||||
|
||||
@@ -56,4 +56,6 @@ pytest-factoryboy==2.6.0
|
||||
pytest-html==4.1.1
|
||||
pytest-asyncio==0.23.5
|
||||
pytest-xdist==3.5.0
|
||||
django-vite==3.0.3
|
||||
autopep8==2.0.4
|
||||
flake8==6.1.0
|
||||
yapf==0.40.2
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^8.46.0",
|
||||
"eslint-plugin-vue": "^8.7.1",
|
||||
"prettier": "^3.2.5",
|
||||
"typescript": "~5.3.3",
|
||||
"vue-cli-plugin-i18n": "^2.3.2",
|
||||
"webpack-bundle-tracker": "3.0.1",
|
||||
|
||||
@@ -9136,6 +9136,11 @@ prepend-http@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
|
||||
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
|
||||
|
||||
prettier@^3.2.5:
|
||||
version "3.2.5"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
|
||||
integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
|
||||
|
||||
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
|
||||
|
||||
Reference in New Issue
Block a user