├── .github ├── release-drafter.yml └── workflows │ ├── build.yml │ ├── pre-release.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── cli.py ├── docs ├── _config.yml ├── bugs_and_features.md ├── configuration.md ├── development.md ├── img │ ├── admin_docs.png │ ├── changeform_carousel.png │ ├── changeform_collapsible.png │ ├── changeform_horizontal_tabs.png │ ├── changeform_single.png │ ├── changeform_vertical_tabs.png │ ├── customise_icon.png │ ├── dashboard.png │ ├── dashboard_mobile.png │ ├── dashboard_tablet.png │ ├── detail_view.png │ ├── history_page.png │ ├── language_chooser.png │ ├── list_view.png │ ├── login.png │ ├── related_modal_bootstrap.png │ ├── side_menu.png │ ├── theme_darkly.png │ ├── theme_simplex.png │ ├── theme_sketchy.png │ ├── theme_slate.png │ ├── top_menu.png │ ├── ui_customiser.png │ └── user_menu.png ├── index.md ├── installation.md └── ui_customisation.md ├── jazzmin ├── __init__.py ├── apps.py ├── compat.py ├── locale │ ├── bg │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── fr │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── hu │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── pt_BR │ │ └── LC_MESSAGES │ │ │ └── django.po │ ├── ru │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── zh_Hans │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── zh_Hant │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── settings.py ├── static │ ├── admin │ │ └── js │ │ │ ├── cancel.js │ │ │ └── popup_response.js │ ├── jazzmin │ │ ├── css │ │ │ └── main.css │ │ ├── img │ │ │ ├── calendar-icons.svg │ │ │ ├── default-log.svg │ │ │ ├── default.jpg │ │ │ ├── icon-calendar.svg │ │ │ ├── icon-changelink.svg │ │ │ └── selector-icons.svg │ │ ├── js │ │ │ ├── change_form.js │ │ │ ├── change_list.js │ │ │ ├── main.js │ │ │ ├── related-modal.js │ │ │ └── ui-builder.js │ │ └── plugins │ │ │ └── bootstrap-show-modal │ │ │ └── bootstrap-show-modal.min.js │ └── vendor │ │ ├── adminlte │ │ ├── css │ │ │ ├── adminlte.min.css │ │ │ └── adminlte.min.css.map │ │ ├── img │ │ │ ├── AdminLTELogo.png │ │ │ ├── icons.png │ │ │ └── user2-160x160.jpg │ │ └── js │ │ │ ├── adminlte.min.js │ │ │ └── adminlte.min.js.map │ │ ├── bootstrap │ │ └── js │ │ │ ├── bootstrap.min.js │ │ │ └── bootstrap.min.js.map │ │ ├── bootswatch │ │ ├── cerulean │ │ │ └── bootstrap.min.css │ │ ├── cosmo │ │ │ └── bootstrap.min.css │ │ ├── cyborg │ │ │ └── bootstrap.min.css │ │ ├── darkly │ │ │ └── bootstrap.min.css │ │ ├── default │ │ │ └── bootstrap.min.css │ │ ├── flatly │ │ │ └── bootstrap.min.css │ │ ├── journal │ │ │ └── bootstrap.min.css │ │ ├── litera │ │ │ └── bootstrap.min.css │ │ ├── lumen │ │ │ └── bootstrap.min.css │ │ ├── lux │ │ │ └── bootstrap.min.css │ │ ├── materia │ │ │ └── bootstrap.min.css │ │ ├── minty │ │ │ └── bootstrap.min.css │ │ ├── morph │ │ │ └── bootstrap.min.css │ │ ├── pulse │ │ │ └── bootstrap.min.css │ │ ├── quartz │ │ │ └── bootstrap.min.css │ │ ├── sandstone │ │ │ └── bootstrap.min.css │ │ ├── simplex │ │ │ └── bootstrap.min.css │ │ ├── sketchy │ │ │ └── bootstrap.min.css │ │ ├── slate │ │ │ └── bootstrap.min.css │ │ ├── solar │ │ │ └── bootstrap.min.css │ │ ├── spacelab │ │ │ └── bootstrap.min.css │ │ ├── superhero │ │ │ └── bootstrap.min.css │ │ ├── united │ │ │ └── bootstrap.min.css │ │ ├── vapor │ │ │ └── bootstrap.min.css │ │ ├── yeti │ │ │ └── bootstrap.min.css │ │ └── zephyr │ │ │ └── bootstrap.min.css │ │ ├── fontawesome-free │ │ ├── css │ │ │ └── all.min.css │ │ └── webfonts │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff2 │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-solid-900.woff2 │ │ │ ├── fa-v4compatibility.ttf │ │ │ └── fa-v4compatibility.woff2 │ │ └── select2 │ │ ├── css │ │ └── select2.min.css │ │ └── js │ │ └── select2.min.js ├── templates │ ├── admin │ │ ├── actions.html │ │ ├── app_index.html │ │ ├── auth │ │ │ └── user │ │ │ │ ├── add_form.html │ │ │ │ └── change_password.html │ │ ├── base.html │ │ ├── base_site.html │ │ ├── change_form.html │ │ ├── change_form_object_tools.html │ │ ├── change_list.html │ │ ├── change_list_object_tools.html │ │ ├── change_list_results.html │ │ ├── date_hierarchy.html │ │ ├── delete_confirmation.html │ │ ├── delete_selected_confirmation.html │ │ ├── edit_inline │ │ │ ├── stacked.html │ │ │ └── tabular.html │ │ ├── filer │ │ │ ├── breadcrumbs.html │ │ │ ├── change_form.html │ │ │ ├── delete_selected_files_confirmation.html │ │ │ ├── file │ │ │ │ └── change_form.html │ │ │ ├── folder │ │ │ │ ├── change_form.html │ │ │ │ └── directory_listing.html │ │ │ ├── image │ │ │ │ └── change_form.html │ │ │ └── tools │ │ │ │ └── detail_info.html │ │ ├── filter.html │ │ ├── import_export │ │ │ ├── base.html │ │ │ ├── change_list.html │ │ │ ├── change_list_export.html │ │ │ ├── change_list_export_item.html │ │ │ ├── change_list_import.html │ │ │ ├── change_list_import_export.html │ │ │ ├── change_list_import_item.html │ │ │ ├── export.html │ │ │ └── import.html │ │ ├── includes │ │ │ ├── fieldset.html │ │ │ └── object_delete_summary.html │ │ ├── index.html │ │ ├── login.html │ │ ├── mptt_filter.html │ │ ├── object_history.html │ │ ├── pagination.html │ │ ├── popup_response.html │ │ ├── search_form.html │ │ ├── solo │ │ │ ├── change_form.html │ │ │ └── object_history.html │ │ └── submit_line.html │ ├── admin_doc │ │ ├── base_docs.html │ │ ├── bookmarklets.html │ │ ├── index.html │ │ ├── missing_docutils.html │ │ ├── model_detail.html │ │ ├── model_index.html │ │ ├── template_detail.html │ │ ├── template_filter_index.html │ │ ├── template_tag_index.html │ │ ├── view_detail.html │ │ └── view_index.html │ ├── jazzmin │ │ ├── includes │ │ │ ├── carousel.html │ │ │ ├── collapsible.html │ │ │ ├── horizontal_tabs.html │ │ │ ├── related_modal.html │ │ │ ├── single.html │ │ │ ├── ui_builder_panel.html │ │ │ └── vertical_tabs.html │ │ └── widgets │ │ │ └── select.html │ └── registration │ │ ├── base.html │ │ ├── logged_out.html │ │ ├── password_change_done.html │ │ ├── password_change_form.html │ │ ├── password_reset_complete.html │ │ ├── password_reset_confirm.html │ │ ├── password_reset_done.html │ │ └── password_reset_form.html ├── templatetags │ ├── __init__.py │ └── jazzmin.py ├── utils.py └── widgets.py ├── mkdocs.yml ├── poetry.lock ├── pyproject.toml └── tests ├── __init__.py ├── conftest.py ├── test_admin_views.py ├── test_app ├── __init__.py ├── library │ ├── __init__.py │ ├── books │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── management │ │ │ ├── __init__.py │ │ │ └── commands │ │ │ │ ├── __init__.py │ │ │ │ └── reset.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_book_library.py │ │ │ ├── 0003_auto_20201015_1222.py │ │ │ ├── 0004_book_pages.py │ │ │ ├── 0005_book_last_print.py │ │ │ ├── 0006_auto_20220327_0814.py │ │ │ ├── 0007_auto_20220715_1109.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── receivers.py │ │ ├── static │ │ │ └── books │ │ │ │ └── img │ │ │ │ ├── icon.png │ │ │ │ ├── logo-login-dark-mode.png │ │ │ │ ├── logo-login.png │ │ │ │ └── logo.png │ │ └── templates │ │ │ └── admin │ │ │ └── loans │ │ │ └── bookloan │ │ │ └── submit_line.html │ ├── factories.py │ ├── loans │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_auto_20201015_1222.py │ │ │ ├── 0003_alter_library_id.py │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── templates │ │ │ └── loans │ │ │ │ └── custom.html │ │ └── views.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py └── requirements.txt ├── test_customisation.py ├── test_init.py ├── test_jazzmin_menus.py ├── test_permissions.py ├── test_settings.py ├── test_templatetags.py ├── test_utils.py └── utils.py /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$RESOLVED_VERSION 🌈' 2 | tag-template: 'v$RESOLVED_VERSION' 3 | categories: 4 | - title: '🚀 Features' 5 | labels: 6 | - 'feature' 7 | - 'enhancement' 8 | - title: '🐛 Bug Fixes' 9 | labels: 10 | - 'fix' 11 | - 'bugfix' 12 | - 'bug' 13 | - title: '🧰 Maintenance' 14 | label: 'chore' 15 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' 16 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. 17 | version-resolver: 18 | major: 19 | labels: 20 | - 'major' 21 | minor: 22 | labels: 23 | - 'minor' 24 | patch: 25 | labels: 26 | - 'patch' 27 | default: patch 28 | template: | 29 | ## Changes 30 | 31 | $CHANGES 32 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Build 4 | on: 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-20.04 13 | strategy: 14 | max-parallel: 5 15 | matrix: 16 | python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] 17 | env: 18 | COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 1 24 | 25 | - name: Set up Python ${{ matrix.python-version }} 26 | uses: actions/setup-python@v5 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | cache: pip 30 | 31 | - name: Install dependencies 32 | run: python -m pip install --upgrade pip tox tox-gh-actions 33 | 34 | - name: Run tests 35 | run: tox 36 | 37 | - name: cache deps 38 | uses: actions/cache@v4 39 | with: 40 | path: ~/.tox 41 | key: deps-${{ hashFiles('**/pyproject.toml') }} 42 | restore-keys: deps-${{ hashFiles('**/pyproject.toml') }} 43 | -------------------------------------------------------------------------------- /.github/workflows/pre-release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Deploy to test.pypi.org 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | # Only allow the latest workflow to run and cancel all others. There is also job-level concurrency 10 | # enabled (see below), which is specified slightly differently. 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | # Build the python package even on PRs to ensure we're able to build the package properly. 17 | build: 18 | runs-on: ubuntu-20.04 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: Set up Python 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version: "3.x" 26 | cache: pip 27 | 28 | - name: Install dependencies 29 | run: python -m pip install --upgrade pip poetry 30 | 31 | - name: Building the wheels 32 | run: | 33 | # Need to check both Test PyPi and GH releases as we need to version bump the patch 34 | # version everytime we merge in a PR, but once we release a new production release, we 35 | # need to bump from the new release. So we grab the latest releases from both sources, 36 | # then reverse sort them to get highest version! Simples :D 37 | LATEST_RELEASE_TEST_PYPI=$(curl -s https://test.pypi.org/rss/project/django-jazzmin/releases.xml | sed -n 's/\s*\([{a,b}0-9.]*\).*/\1/p' | head -n 2 | xargs) 38 | LATEST_RELEASE_GITHUB=$(curl -s "https://api.github.com/repos/farridav/django-jazzmin/tags" | jq -r '.[0].name[1:]') 39 | LATEST_RELEASE=$(printf "${LATEST_RELEASE_GITHUB}\n${LATEST_RELEASE_TEST_PYPI}" | sort -V -r | head -n 1) 40 | 41 | # Now we can bump the version correctly to release a new version nicely base on the 42 | # latest GH release. 43 | poetry version $LATEST_RELEASE 44 | poetry version prerelease # Using `prerelease` rather than `prepatch` due to a bug in Poetry (latest checked 1.8.1 - https://github.com/python-poetry/poetry/issues/879) 45 | poetry build 46 | 47 | - name: Save build 48 | uses: actions/cache/save@v4 49 | id: build-cache 50 | with: 51 | path: | 52 | dist/ 53 | key: cache-${{ github.run_id }}-${{ github.run_attempt }} 54 | 55 | deploy: 56 | runs-on: ubuntu-20.04 57 | needs: build 58 | steps: 59 | - uses: actions/checkout@v4 60 | 61 | - name: Set up Python 62 | uses: actions/setup-python@v5 63 | with: 64 | python-version: "3.x" 65 | cache: pip 66 | 67 | - name: Install dependencies 68 | run: python -m pip install --upgrade pip poetry 69 | 70 | - name: Get build 71 | uses: actions/cache/restore@v4 72 | with: 73 | path: | 74 | dist/ 75 | key: cache-${{ github.run_id }}-${{ github.run_attempt }} 76 | 77 | - name: Configure Poetry test repo 78 | run: poetry config repositories.test_pypi https://test.pypi.org/legacy/ 79 | 80 | - name: Deploy to testpypi.org 81 | if: github.ref == 'refs/heads/main' 82 | run: poetry publish -r test_pypi --dist-dir dist/ --username __token__ --password ${{ secrets.TEST_PYPI_TOKEN }} || true 83 | 84 | - name: Deploy to testpypi.org (Dry Run) 85 | if: github.ref != 'refs/heads/main' 86 | run: poetry publish -r test_pypi --dist-dir dist/ --username __token__ --password ${{ secrets.TEST_PYPI_TOKEN }} || true 87 | 88 | update_release_draft: 89 | permissions: 90 | contents: write 91 | pull-requests: read 92 | runs-on: ubuntu-latest 93 | needs: deploy 94 | if: github.ref == 'refs/heads/main' 95 | steps: 96 | - uses: release-drafter/release-drafter@v5 97 | with: 98 | config-name: release-drafter.yml 99 | disable-autolabeler: true 100 | env: 101 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 102 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Deploy to pypi.org 3 | on: 4 | release: 5 | types: published 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-20.04 10 | steps: 11 | - uses: actions/checkout@v4 12 | 13 | - name: Set up Python 14 | uses: actions/setup-python@v5 15 | with: 16 | python-version: "3.x" 17 | cache: pip 18 | 19 | - name: Install dependencies 20 | run: python -m pip install --upgrade pip poetry 21 | 22 | - name: Deploy to pypi.org 23 | run: | 24 | poetry version ${GITHUB_REF_NAME/#v} 25 | poetry publish --build --username __token__ --password ${{ secrets.PYPI_TOKEN }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | *.pyc 3 | .DS_Store 4 | .coverage 5 | .idea 6 | .tox 7 | .venv 8 | .env 9 | .vscode 10 | .vim 11 | /diffs 12 | /build 13 | /dist 14 | *.reports 15 | __pycache__ 16 | _resource 17 | admin_templates 18 | admindocs_templates 19 | *.sqlite3 20 | tests/test_app/static/ 21 | .python-version 22 | .mypy_cache 23 | .ruff_cache 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CYAN ?= \033[0;36m 2 | COFF ?= \033[0m 3 | 4 | .PHONY: deps lint check test help test_app test_user 5 | .EXPORT_ALL_VARIABLES: 6 | 7 | .DEFAULT: help 8 | help: ## Display help message 9 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-30s$(COFF) %s\n", $$1, $$2}' 10 | 11 | # Check whether there is a poetry env and it is a directory (env info may persist even after removing env) 12 | environment := $(shell [ -d "$$(poetry env info -p)" ] && echo "poetry run") 13 | 14 | check-venv: 15 | $(if $(environment),, $(error No poetry environment found, either run "make deps" or "poetry install")) 16 | 17 | deps: ## Install dependencies 18 | @printf "$(CYAN)Updating python deps$(COFF)\n" 19 | pip3 install -U pip poetry 20 | poetry install 21 | 22 | lint: check-venv ## Lint the code 23 | @printf "$(CYAN)Auto-formatting with ruff$(COFF)\n" 24 | $(environment) ruff format jazzmin tests 25 | $(environment) ruff check jazzmin tests --fix 26 | 27 | check: check-venv ## Check code quality 28 | @printf "$(CYAN)Running static code analysis$(COFF)\n" 29 | $(environment) ruff format --check jazzmin tests 30 | $(environment) ruff check jazzmin tests 31 | $(environment) mypy jazzmin tests --ignore-missing-imports 32 | 33 | test: check-venv ## Run the test suite 34 | @printf "$(CYAN)Running test suite$(COFF)\n" 35 | $(environment) pytest 36 | 37 | test_app: check-venv ## Run the test app 38 | @printf "$(CYAN)Running test app$(COFF)\n" 39 | $(environment) python tests/test_app/manage.py migrate 40 | $(environment) python tests/test_app/manage.py runserver_plus 41 | 42 | test_user: ## Make the test user 43 | $(environment) python tests/test_app/manage.py shell -c "from django.contrib.auth.models import User; User.objects.create_superuser('test@test.com', password='test')" 44 | -------------------------------------------------------------------------------- /cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import subprocess 5 | from itertools import chain 6 | 7 | import click 8 | import django 9 | import polib 10 | 11 | THIS_DIR = os.path.dirname(__file__) 12 | LOCALE_DIR = os.path.join(THIS_DIR, "jazzmin", "locale") 13 | LOCALES = os.listdir(LOCALE_DIR) 14 | DJANGO_PATH = django.__path__[0] 15 | 16 | 17 | @click.group() 18 | def main(): 19 | pass 20 | 21 | 22 | @main.command() 23 | @click.option("--prune", type=click.Choice(LOCALES), help="locale to prune", required=True) 24 | def locales(prune: str): 25 | """ 26 | Remove the django provided strings 27 | 28 | e.g - ./cli.py locales --prune de 29 | """ 30 | our_po = polib.pofile(os.path.join(LOCALE_DIR, prune, "LC_MESSAGES", "django.po")) 31 | admin_po = polib.pofile(os.path.join(DJANGO_PATH, "contrib", "admin", "locale", "en", "LC_MESSAGES", "django.po")) 32 | admindocs_po = polib.pofile( 33 | os.path.join( 34 | DJANGO_PATH, 35 | "contrib", 36 | "admindocs", 37 | "locale", 38 | "en", 39 | "LC_MESSAGES", 40 | "django.po", 41 | ) 42 | ) 43 | existing_strings = {x.msgid for x in chain(admin_po, admindocs_po)} 44 | new_po = polib.POFile() 45 | new_po.metadata = our_po.metadata 46 | for po in our_po: 47 | if po.msgid not in existing_strings: 48 | new_po.append(po) 49 | 50 | new_po.save(os.path.join(LOCALE_DIR, prune, "LC_MESSAGES", "django.po")) 51 | 52 | 53 | @main.command() 54 | def templates(): 55 | """ 56 | Generate diffs/patch files for all the templates we override, useful for seeing whats changed 57 | 58 | ./cli.py templates --diff 59 | """ 60 | diffs = os.path.join(THIS_DIR, "diffs") 61 | templates = { 62 | os.path.join(THIS_DIR, "jazzmin", "templates", "admin"): os.path.join( 63 | DJANGO_PATH, "contrib", "admin", "templates", "admin" 64 | ), 65 | os.path.join(THIS_DIR, "jazzmin", "templates", "admin_doc"): os.path.join( 66 | DJANGO_PATH, "contrib", "admindocs", "templates", "admin_doc" 67 | ), 68 | } 69 | 70 | for jazzmin_dir, django_dir in templates.items(): 71 | for template in [os.path.join(dp, f) for dp, dn, filenames in os.walk(jazzmin_dir) for f in filenames]: 72 | original = template.replace(jazzmin_dir, django_dir) 73 | if os.path.isfile(original): 74 | result = subprocess.run( 75 | ["diff", "-u", "-w", "--suppress-common-lines", original, template], 76 | stdout=subprocess.PIPE, 77 | ) 78 | out_file = template.replace(jazzmin_dir, diffs) + ".patch" 79 | os.makedirs(os.path.dirname(out_file), exist_ok=True) 80 | 81 | with open(out_file, "wb+") as fp: 82 | fp.write(result.stdout) 83 | 84 | 85 | if __name__ == "__main__": 86 | main() 87 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /docs/bugs_and_features.md: -------------------------------------------------------------------------------- 1 | # Bugs & Features 2 | 3 | ## Reporting bugs 4 | 5 | When reporting bugs, or compatibility issues, here is a general guide on the best way to do it. 6 | 7 | First of all, ask yourself these questions: 8 | 9 | 1. Does your app behave as expected if `jazzmin` is commented out of your `INSTALLED_APPS`? 10 | 2. Can you reproduce the problem locally in our test app, and submit it as a Pull request for us to work against (see [development.md](./development.md)) ? 11 | 3. Can you add a failing test for the problem (see [development.md](./development.md))? 12 | 4. Can you screenshot the issue and attach it to an issue or pull request? 13 | 5. Can you solve the problem (and not introduce other issues) by changing HTML, or CSS, or JS 14 | 15 | If you can solve the problem using CSS/JS then you can temporarily use "custom CSS/JS" within jazzmin settings, see [configuration.md](./configuration.md) until we have the fix released 16 | 17 | ## Features 18 | 19 | We welcome new features, here is a list of guidelines to consider: 20 | 21 | 1. Avoid writing too much CSS (We have CSS frameworks that we make use of, namely adminLTE & Bootstrap) 22 | 2. Look for components in AdminLTE first, we try to keep in-line with that, failing that, bootstrap has a lot to offer 23 | 3. Ensure that new features are *off* by default 24 | 4. Ensure that new features are well documented 25 | i) Add a section to [configuration.md](./configuration.md) if necessary 26 | ii) Add the new feature into the embedded test_app 27 | 5. Ensure that all configuration is optional 28 | 6. Ensure that any new strings are translated (but ideally try to use icons, or fallback on the comprehensive translations from Django) 29 | 30 | When making changes, see if you can achieve your goal by removing code, failing that, try changing code, failing that, add new code 31 | 32 | We prefer to use HTML first, failing that, use CSS, failing that, use JavaScript (This approach helps with maintainability) 33 | 34 | Some useful links for feature development: 35 | 36 | - [https://adminlte.io/themes/v3/index3.html](https://adminlte.io/themes/v3/index3.html) 37 | - [https://adminlte.io/docs/3.0/index.html](https://adminlte.io/docs/3.0/index.html) 38 | - [Font awesome 5.13.0 free icons](https://fontawesome.com/icons?d=gallery&m=free&v=5.0.0,5.0.1,5.0.10,5.0.11,5.0.12,5.0.13,5.0.2,5.0.3,5.0.4,5.0.5,5.0.6,5.0.7,5.0.8,5.0.9,5.1.0,5.1.1,5.2.0,5.3.0,5.3.1,5.4.0,5.4.1,5.4.2,5.13.0,5.12.0,5.11.2,5.11.1,5.10.0,5.9.0,5.8.2,5.8.1,5.7.2,5.7.1,5.7.0,5.6.3,5.5.0,5.4.2) 39 | - [https://getbootstrap.com/docs/4.5/getting-started/introduction/](https://getbootstrap.com/docs/4.5/getting-started/introduction/) 40 | -------------------------------------------------------------------------------- /docs/development.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | ## Installation 4 | 5 | This project manages dependencies using [poetry](https://python-poetry.org/) 6 | 7 | Ensure you have poetry installed (`pip install poetry`) 8 | 9 | Then get setup with `poetry install` 10 | 11 | git clone git@github.com:farridav/django-jazzmin.git 12 | poetry install 13 | 14 | ## Running the test project 15 | 16 | Setup db tables etc. 17 | 18 | python tests/test_app/manage.py migrate 19 | 20 | Generate test data 21 | 22 | python tests/test_app/manage.py reset 23 | 24 | Run development server (with werkzeug debugger) 25 | 26 | python tests/test_app/manage.py runserver_plus 27 | 28 | ## Running the tests 29 | 30 | Tests are run via github actions on any pull request into `main`, and are written for use with the [pytest](https://docs.pytest.org/en/latest/) 31 | framework, we should have good enough tests for you to base your own off of, though where we are lacking, feel free to contribute, 32 | but keep it clean, concise and simple, leave the magic to the wizards. 33 | 34 | Run the test suite with your current python interpreter and Django version using `pytest` or target an individual test 35 | with `pytest -k my_test_name` 36 | 37 | Run against all supported Python and Django Versions using `tox` 38 | 39 | ## Contribution guidelines 40 | 41 | - Fork the project 42 | - Make a pull request against this repositories `main` branch, 43 | - Include tests unless its a trivial change 44 | - Add a screenshot if your proposing UI changes 45 | - Demonstrate the change within the `test_app` if possible 46 | - No breaking changes please 47 | 48 | ## Coding guidelines 49 | 50 | - autoformat your code with [black](https://github.com/psf/black) 51 | - When fixing something display related, please bear the following in mind: 52 | - Try fixing the problem using HTML, else CSS, else JS 53 | - Try removing code, else changing code, else adding code 54 | 55 | ## Serving documentation locally 56 | 57 | You can serve the docs locally using `mkdocs serve -a localhost:8001` and visiting [http://localhost:8001](http://localhost:8001) 58 | 59 | ## Translations 60 | 61 | Working with translations in jazzmin is, a bit unorthodox, as we are overriding djangos templates, so it looks like we have a lot of strings that need translating, 62 | but in-fact they already have translation strings in Django, heres the process for dealing with translations, though we recommend not adding new strings that need 63 | translating if possible, and use suitable iconography instead (See [Font Awesome 5.13.0 free icons](https://fontawesome.com/icons?d=gallery&m=free&v=5.0.0,5.0.1,5.0.10,5.0.11,5.0.12,5.0.13,5.0.2,5.0.3,5.0.4,5.0.5,5.0.6,5.0.7,5.0.8,5.0.9,5.1.0,5.1.1,5.2.0,5.3.0,5.3.1,5.4.0,5.4.1,5.4.2,5.13.0,5.12.0,5.11.2,5.11.1,5.10.0,5.9.0,5.8.2,5.8.1,5.7.2,5.7.1,5.7.0,5.6.3,5.5.0,5.4.2)), 64 | or use a string that is already translated upstream in Django. 65 | 66 | ### Adding a new language 67 | 68 | 1. cd into the jazzmin folder 69 | 2. Add the desired language directory e.g mkdir -p locale/de/LC_MESSAGES 70 | 3. Run django-admin makemessages 71 | 4. cd ../ 72 | 5. Run ./cli.py locales --prune de to remove the django provided strings 73 | 6. Go through the strings in the locale file, any that are not genuinely new strings introduced by jazzmin, find them in the codebase, and try making them match the ones provided in djangos admin/admin docs translation files 74 | - [Django admin docs translations example for German language](https://raw.githubusercontent.com/django/django/main/django/contrib/admin/locale/de/LC_MESSAGES/django.po) 75 | 76 | Once you have finished, run `makemessages` again, until the file contains ONLY unique strings to jazzmin, there should only be a handful 77 | -------------------------------------------------------------------------------- /docs/img/admin_docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/admin_docs.png -------------------------------------------------------------------------------- /docs/img/changeform_carousel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/changeform_carousel.png -------------------------------------------------------------------------------- /docs/img/changeform_collapsible.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/changeform_collapsible.png -------------------------------------------------------------------------------- /docs/img/changeform_horizontal_tabs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/changeform_horizontal_tabs.png -------------------------------------------------------------------------------- /docs/img/changeform_single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/changeform_single.png -------------------------------------------------------------------------------- /docs/img/changeform_vertical_tabs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/changeform_vertical_tabs.png -------------------------------------------------------------------------------- /docs/img/customise_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/customise_icon.png -------------------------------------------------------------------------------- /docs/img/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/dashboard.png -------------------------------------------------------------------------------- /docs/img/dashboard_mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/dashboard_mobile.png -------------------------------------------------------------------------------- /docs/img/dashboard_tablet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/dashboard_tablet.png -------------------------------------------------------------------------------- /docs/img/detail_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/detail_view.png -------------------------------------------------------------------------------- /docs/img/history_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/history_page.png -------------------------------------------------------------------------------- /docs/img/language_chooser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/language_chooser.png -------------------------------------------------------------------------------- /docs/img/list_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/list_view.png -------------------------------------------------------------------------------- /docs/img/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/login.png -------------------------------------------------------------------------------- /docs/img/related_modal_bootstrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/related_modal_bootstrap.png -------------------------------------------------------------------------------- /docs/img/side_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/side_menu.png -------------------------------------------------------------------------------- /docs/img/theme_darkly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/theme_darkly.png -------------------------------------------------------------------------------- /docs/img/theme_simplex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/theme_simplex.png -------------------------------------------------------------------------------- /docs/img/theme_sketchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/theme_sketchy.png -------------------------------------------------------------------------------- /docs/img/theme_slate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/theme_slate.png -------------------------------------------------------------------------------- /docs/img/top_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/top_menu.png -------------------------------------------------------------------------------- /docs/img/ui_customiser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/ui_customiser.png -------------------------------------------------------------------------------- /docs/img/user_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/docs/img/user_menu.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Jazzmin 2 | 3 | Welcome to Jazzmin, intended as a drop-in app to jazz up your django admin site, with plenty of things you can easily 4 | customise, including a built-in UI customizer 5 | 6 | ## Features 7 | 8 | - Drop-in admin skin, all configuration optional 9 | - Select2 drop-downs 10 | - Bootstrap 5 & AdminLTE UI components 11 | - Search bar for any given model admin 12 | - Modal windows instead of popups 13 | - Customisable side menu 14 | - Customisable top menu 15 | - Customisable user menu 16 | - Responsive 17 | - Customisable UI (via Live UI changes, or custom CSS/JS) 18 | - Based on the latest [adminlte](https://adminlte.io/) + [bootstrap](https://getbootstrap.com/) 19 | 20 | ## Demo 21 | 22 | Live demo https://django-jazzmin-test.onrender.com 23 | 24 | **Username**: test@test.com 25 | 26 | **Password**: test 27 | 28 | *Note: Data resets nightly* 29 | 30 | *Note: ☕ If the app seems sleepy, give it a minute - it's just having its power nap on the free tier.* 31 | 32 | You can also view the demo app by cloning the repository, and running the following commands: 33 | 34 | ```bash 35 | poetry install 36 | ./tests/test_app/manage.py migrate 37 | ./tests/test_app/manage.py reset 38 | ./tests/test_app/manage.py runserver_plus 39 | ``` 40 | 41 | ## Screenshots 42 | 43 | ### Dashboard 44 | 45 | [![dashboard](./img/dashboard.png)](./img/dashboard.png) 46 | 47 | ### List view 48 | 49 | [![table list](./img/list_view.png)](./img/list_view.png) 50 | 51 | ### Detail view 52 | 53 | [![form page](./img/detail_view.png)](./img/detail_view.png) 54 | 55 | ### History page 56 | 57 | [![history page](./img/history_page.png)](./img/history_page.png) 58 | 59 | ### Modal windows 60 | 61 | [![Modal windows](./img/related_modal_bootstrap.png)](./img/related_modal_bootstrap.png) 62 | 63 | ### Login view 64 | 65 | [![login](./img/login.png)](./img/login.png) 66 | 67 | ### UI Customiser 68 | 69 | [![UI Customiser](./img/ui_customiser.png)](./img/ui_customiser.png) 70 | 71 | ### Mobile layout 72 | 73 | [![Mobile layout](./img/dashboard_mobile.png)](./img/dashboard_mobile.png) 74 | 75 | ### Tablet layout 76 | 77 | [![Table Layout](./img/dashboard_tablet.png)](./img/dashboard_tablet.png) 78 | 79 | ### Admin docs (if installed) 80 | 81 | [![Admin docs](./img/admin_docs.png)](./img/admin_docs.png) 82 | 83 | ## Thanks 84 | 85 | This was initially a Fork of <https://github.com/wuyue92tree/django-adminlte-ui> that we refactored so much we thought it 86 | deserved its own package, big thanks to @wuyue92tree for all of his initial hard work, we are still patching into that 87 | project were possible, but this project is taking a slightly different direction. 88 | 89 | - Based on AdminLTE 3: <https://adminlte.io/> 90 | - Using Bootstrap 5: <https://getbootstrap.com/> 91 | - Using Font Awesome 5: <https://fontawesome.com/> 92 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | Install the latest [pypi](https://pypi.org/project/django-jazzmin/) release with `pip install -U django-jazzmin` 4 | 5 | Add `jazzmin` to your `INSTALLED_APPS` before `django.contrib.admin`, and Voila! 6 | 7 | ```python 8 | INSTALLED_APPS = [ 9 | 'jazzmin', 10 | 11 | 'django.contrib.admin', 12 | [...] 13 | ] 14 | ``` 15 | 16 | See [configuration](./configuration.md) for optional customisation of the theme 17 | 18 | See [development](./development.md) for notes on setting up for development 19 | -------------------------------------------------------------------------------- /jazzmin/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # We automatically grab the version of `django-jazzmin` from the package manager instead of 4 | # hard coding it. The method for determining the version changed since PY3.8. N.B. For 5 | # development versions of `django-jazzmin`, the version will be 0.0.0 (see pyproject.toml) as it's 6 | # not technically installed. 7 | if sys.version_info >= (3, 8): 8 | from importlib.metadata import version as package_version 9 | 10 | version = package_version("django-jazzmin") 11 | else: 12 | import pkg_resources 13 | 14 | version = pkg_resources.get_distribution("django-jazzmin").version 15 | -------------------------------------------------------------------------------- /jazzmin/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | __all__ = ["JazzminConfig"] 6 | 7 | 8 | class JazzminConfig(AppConfig): 9 | name = "jazzmin" 10 | label = "jazzmin" 11 | verbose_name = "Jazzmin" 12 | -------------------------------------------------------------------------------- /jazzmin/compat.py: -------------------------------------------------------------------------------- 1 | try: 2 | from django.urls import reverse, resolve, NoReverseMatch # NOQA 3 | except ImportError: 4 | from django.core.urlresolvers import reverse, resolve, NoReverseMatch # NOQA 5 | -------------------------------------------------------------------------------- /jazzmin/locale/bg/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/locale/bg/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /jazzmin/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /jazzmin/locale/de/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # 2 | msgid "" 3 | msgstr "" 4 | "Project-Id-Version: \n" 5 | "Report-Msgid-Bugs-To: \n" 6 | "POT-Creation-Date: 2020-10-03 17:04+0100\n" 7 | "PO-Revision-Date: 2020-09-22 10:18+0200\n" 8 | "Last-Translator: \n" 9 | "Language-Team: \n" 10 | "Language: de\n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 15 | "X-Generator: Poedit 2.2.1\n" 16 | 17 | #: templates/admin/base.html:125 18 | msgid "Account" 19 | msgstr "Konto" 20 | 21 | #: templates/admin/base.html:143 22 | msgid "See Profile" 23 | msgstr "Profil anzeigen" 24 | 25 | #: templates/admin/base.html:183 templates/admin/index.html:6 26 | #: templates/admin/index.html:11 27 | msgid "Dashboard" 28 | msgstr "Dashboard" 29 | 30 | #: templates/admin/base.html:294 31 | msgid "Jazzmin version" 32 | msgstr "Jazzmin Version" 33 | 34 | #: templates/admin/base.html:297 35 | msgid "Copyright" 36 | msgstr "" 37 | 38 | #: templates/admin/base.html:297 39 | msgid "All rights reserved." 40 | msgstr "Alle Rechte vorbehalten." 41 | 42 | #: templates/admin/base.html:313 43 | msgid "UI Configuration" 44 | msgstr "UI Konfiguration" 45 | 46 | #: templates/admin/base.html:317 47 | msgid "Copy this info your settings file to persist these UI changes" 48 | msgstr "" 49 | "Übernehmen sie dies in Ihre Einstellungs-Datei, um die UI-Anpassungen " 50 | "persistent zu machen" 51 | 52 | #: templates/admin/index.html:90 53 | #| msgid "%(entry.action_time|timesince)s ago" 54 | msgid "%(timesince)s ago" 55 | msgstr "%(timesince)s vor" 56 | 57 | #: templates/admin/submit_line.html:8 58 | msgid "Actions" 59 | msgstr "Aktionen" 60 | 61 | #: templates/admin_doc/template_detail.html:13 62 | #, python-format 63 | msgid "Template: <q>%(name)s</q>" 64 | msgstr "Vorlage: <q>%(name)s</q>" 65 | 66 | #. Translators: Search is not a verb here, it qualifies path (a search path) 67 | #: templates/admin_doc/template_detail.html:17 68 | #, python-format 69 | msgid "Search path for template <q>%(name)s</q>:" 70 | msgstr "Suchpfad für Vorlage <q>%(name)s</q>:" 71 | 72 | #: templates/admin_doc/template_filter_index.html:37 73 | #: templates/admin_doc/view_index.html:43 74 | #, python-format 75 | msgid "" 76 | "View function: <code>%(full_name)s</code>. Name: <code>%(url_name)s</code>." 77 | msgstr "" 78 | "View-Funktion: <code>%(full_name)s</code>. Name: <code>%(url_name)s</code>." 79 | 80 | #: templatetags/jazzmin.py:390 81 | #, python-brace-format 82 | msgid "Added {name} “{object}”." 83 | msgstr "{name} “{object}” hinzugefügt." 84 | 85 | #: templatetags/jazzmin.py:406 86 | #, python-brace-format 87 | msgid "Deleted “{object}”." 88 | msgstr "“{object}” gelöscht." 89 | 90 | #: utils.py:66 91 | #, python-brace-format 92 | msgid "Could not reverse url from {instance}" 93 | msgstr "Url für {instance} könnte nicht gefunden werden" 94 | -------------------------------------------------------------------------------- /jazzmin/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /jazzmin/locale/es/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # 2 | msgid "" 3 | msgstr "" 4 | "Project-Id-Version: PACKAGE VERSION\n" 5 | "Report-Msgid-Bugs-To: \n" 6 | "POT-Creation-Date: 2020-10-03 17:04+0100\n" 7 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 8 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 9 | "Language-Team: LANGUAGE <LL@li.org>\n" 10 | "Language: \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 15 | 16 | #: templates/admin/base.html:125 17 | msgid "Account" 18 | msgstr "Cuenta" 19 | 20 | #: templates/admin/base.html:143 21 | msgid "See Profile" 22 | msgstr "Ver perfil" 23 | 24 | #: templates/admin/base.html:183 templates/admin/index.html:6 25 | #: templates/admin/index.html:11 26 | msgid "Dashboard" 27 | msgstr "Panel de control" 28 | 29 | #: templates/admin/base.html:294 30 | msgid "Jazzmin version" 31 | msgstr "Versión de Jazzmin" 32 | 33 | #: templates/admin/base.html:297 34 | msgid "Copyright" 35 | msgstr "" 36 | 37 | #: templates/admin/base.html:297 38 | msgid "All rights reserved." 39 | msgstr "Todos los derechos reservados." 40 | 41 | #: templates/admin/base.html:313 42 | msgid "UI Configuration" 43 | msgstr "Configuración de la IU" 44 | 45 | #: templates/admin/base.html:317 46 | msgid "Copy this info your settings file to persist these UI changes" 47 | msgstr "" 48 | "Copia esta información en tu archivo settings para mantener los cambios en " 49 | "la IU" 50 | 51 | #: templates/admin/index.html:90 52 | #| msgid "%(entry.action_time|timesince)s ago" 53 | msgid "%(timesince)s ago" 54 | msgstr "Hace %(timesince)s" 55 | 56 | #: templates/admin/submit_line.html:8 57 | msgid "Actions" 58 | msgstr "Acciones" 59 | 60 | #: templates/admin_doc/template_detail.html:13 61 | #, python-format 62 | msgid "Template: <q>%(name)s</q>" 63 | msgstr "Plantilla: <q>%(name)s</q>" 64 | 65 | #. Translators: Search is not a verb here, it qualifies path (a search path) 66 | #: templates/admin_doc/template_detail.html:17 67 | #, python-format 68 | msgid "Search path for template <q>%(name)s</q>:" 69 | msgstr "Buscar ruta para plantilla <q>%(name)s</q>:" 70 | 71 | #: templates/admin_doc/template_filter_index.html:37 72 | #: templates/admin_doc/view_index.html:43 73 | #, python-format 74 | msgid "" 75 | "View function: <code>%(full_name)s</code>. Name: <code>%(url_name)s</code>." 76 | msgstr "" 77 | "Ver función: <code>%(full_name)s</code>. Nombre: <code>%(url_name)s</code>." 78 | 79 | #: templatetags/jazzmin.py:390 80 | #, python-brace-format 81 | msgid "Added {name} “{object}”." 82 | msgstr "Añadido {name} “{object}”." 83 | 84 | #: templatetags/jazzmin.py:406 85 | #, python-brace-format 86 | msgid "Deleted “{object}”." 87 | msgstr "“{object}” borrado" 88 | 89 | #: utils.py:66 90 | #, python-brace-format 91 | msgid "Could not reverse url from {instance}" 92 | msgstr "No se pudo obtener la url para {instance}" 93 | -------------------------------------------------------------------------------- /jazzmin/locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /jazzmin/locale/fr/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # This file is distributed under the same license as the Django package. 2 | # 3 | # Translators: 4 | # Bruno Brouard <annoa.b@gmail.com>, 2021 5 | # Claude Paroz <claude@2xlibre.net>, 2013-2020 6 | # Claude Paroz <claude@2xlibre.net>, 2011,2013 7 | # Jannis Leidel <jannis@leidel.info>, 2011 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: django\n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2021-11-29 17:38+0100\n" 13 | "PO-Revision-Date: 2021-03-04 20:53+0000\n" 14 | "Last-Translator: Bruno Brouard <annoa.b@gmail.com>\n" 15 | "Language-Team: French (http://www.transifex.com/django/django/language/fr/)\n" 16 | "Language: fr\n" 17 | "MIME-Version: 1.0\n" 18 | "Content-Type: text/plain; charset=UTF-8\n" 19 | "Content-Transfer-Encoding: 8bit\n" 20 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" 21 | 22 | 23 | msgid "First, enter a username and password. Then, you'll be able to edit more user options." 24 | msgstr "" 25 | "Saisissez tout d’abord un nom d’utilisateur et un mot de passe. Vous pourrez " 26 | "ensuite modifier plus d’options." 27 | 28 | msgid "Account" 29 | msgstr "Compte utilisateur" 30 | 31 | msgid "See Profile" 32 | msgstr "Voir le profil" 33 | 34 | msgid "Dashboard" 35 | msgstr "Tableau de bord" 36 | 37 | msgid "Jazzmin version" 38 | msgstr "Version de Jazzmin" 39 | 40 | msgid "Copyright" 41 | msgstr "Copyright" 42 | 43 | msgid "All rights reserved." 44 | msgstr "Tous droits réservés." 45 | 46 | msgid "UI Configuration" 47 | msgstr "Configuration de l'interface" 48 | 49 | msgid "Copy this info your settings file to persist these UI changes" 50 | msgstr "" 51 | "Copiez cette configuration dans votre fichier de paramètres pour conserver " 52 | "ces modifications de l'interface utilisateur" 53 | 54 | msgid "Confirm Import" 55 | msgstr "Confirmer l'import" 56 | 57 | msgid "Actions" 58 | msgstr "Actions" 59 | 60 | msgid "Some rows failed to validate" 61 | msgstr "Certaines lignes n'ont pas réussi à valider" 62 | 63 | msgid "Please correct these errors in your data where possible, then reupload it using the form above." 64 | msgstr "Veuillez corriger ces erreurs dans vos données, puis re téléchargez le à l'aide du formulaire ci-dessus." 65 | 66 | msgid "Row" 67 | msgstr "Ligne" 68 | 69 | msgid "Non field specific" 70 | msgstr "Non spécifique à un champ" 71 | 72 | #, python-format 73 | msgid "%(timesince)s ago" 74 | msgstr "Depuis %(timesince)s" 75 | 76 | msgid "This object doesn't have a change history. It probably wasn't added via this admin site." 77 | msgstr "" 78 | "Cet objet n’a pas d’historique de modification. Il n’a probablement pas été " 79 | "ajouté au moyen de ce site d’administration." 80 | 81 | msgid "Popup closing..." 82 | msgstr "Fenêtre en cours de fermeture…" 83 | 84 | msgid "The admin documentation system requires Python's <a href=\"%(link)s\">docutils</a> library." 85 | msgstr "Le système de documentation de l'interface d'administration nécessite la bibliothèque Python <a href=\"%(link)s\">docutils</a>." 86 | 87 | msgid "View function: <code>%(full_name)s</code>. Name: <code>%(url_name)s</code>." 88 | msgstr "" 89 | "\n" 90 | "Fonction de vue : <code>%(full_name)s</code>. Nom : <code>%(url_name)s</code>.\n" 91 | 92 | msgid "General" 93 | msgstr "Général" 94 | 95 | msgid "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." 96 | msgstr "Pour des raisons de sécurité, saisissez votre ancien mot de passe puis votre nouveau mot de passe à deux reprises afin de vérifier qu’il est correctement saisi." 97 | 98 | msgid "Deleted “{object}”." 99 | msgstr "« {object} » supprimé." 100 | 101 | #, python-brace-format 102 | msgid "Could not reverse url from {instance}" 103 | msgstr "Impossible de résoudre l'URL de {instance}" 104 | 105 | -------------------------------------------------------------------------------- /jazzmin/locale/hu/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/locale/hu/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /jazzmin/locale/ru/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/locale/ru/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /jazzmin/locale/ru/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # 2 | msgid "" 3 | msgstr "" 4 | "Project-Id-Version: django\n" 5 | "Report-Msgid-Bugs-To: \n" 6 | "POT-Creation-Date: 2021-03-12 00:37+1000\n" 7 | "PO-Revision-Date: 2020-11-14 00:53+0800\n" 8 | "Last-Translator: HurmaDev <nuwetsky@gmail.com>\n" 9 | "Language-Team: \n" 10 | "Language: ru\n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 15 | "X-Generator: Poedit 2.4.2\n" 16 | 17 | #: templates/admin/auth/user/add_form.html:6 18 | msgid "" 19 | "First, enter a username and password. Then, you'll be able to edit more user" 20 | " options." 21 | msgstr "" 22 | "Сначала введите имя пользователя и пароль, после чего вы сможете изменить " 23 | "остальную информацию о пользователе." 24 | 25 | #: templates/admin/base.html:151 26 | msgid "Account" 27 | msgstr "Аккаунт" 28 | 29 | #: templates/admin/base.html:169 30 | msgid "See Profile" 31 | msgstr "Профиль" 32 | 33 | #: templates/admin/base.html:209 templates/admin/index.html:7 34 | #: templates/admin/index.html:12 35 | msgid "Dashboard" 36 | msgstr "Админпанель" 37 | 38 | #: templates/admin/base.html:322 39 | msgid "Jazzmin version" 40 | msgstr "Jazzmin Version" 41 | 42 | #: templates/admin/base.html:325 43 | msgid "Copyright" 44 | msgstr "" 45 | 46 | #: templates/admin/base.html:325 47 | msgid "All rights reserved." 48 | msgstr "Все права защищены." 49 | 50 | #: templates/admin/base.html:341 51 | msgid "UI Configuration" 52 | msgstr "Настройки UI" 53 | 54 | #: templates/admin/base.html:345 55 | msgid "Copy this info your settings file to persist these UI changes" 56 | msgstr "" 57 | "Скопируйте этот текст в свои настройки проекта, чтобы применить изменения" 58 | 59 | #: templates/admin/edit_inline/stacked.html:30 60 | msgid "New" 61 | msgstr "Новый" 62 | 63 | #: templates/admin/submit_line.html:9 64 | msgid "Actions" 65 | msgstr "Действия" 66 | 67 | #: templates/admin/index.html:91 68 | #, fuzzy, python-format 69 | #| msgid "%(timesince)s ago" 70 | msgid "%(timesince)s ago" 71 | msgstr "%(timesince) назад" 72 | 73 | #: templates/admin/object_history.html:58 74 | msgid "" 75 | "This object doesn't have a change history. It probably wasn't added via this" 76 | " admin site." 77 | msgstr "" 78 | "У этого объекта нет истории изменений. Вероятно, он был добавлен не через " 79 | "эту админ-панель." 80 | 81 | #: templates/admin/popup_response.html:5 82 | msgid "Popup closing..." 83 | msgstr "Закрытие всплывающего окна..." 84 | 85 | #: templates/admin_doc/view_index.html:28 86 | #, python-format 87 | msgid "Views by namespace %(name)" 88 | msgstr "Представления по пространству имён %(name)" 89 | 90 | #: templates/admin_doc/view_index.html:30 91 | #, python-format 92 | msgid "Views by empty namespace" 93 | msgstr "Представления по пустому пространству имён" 94 | 95 | #: templates/admin_doc/template_filter_index.html:37 96 | #: templates/admin_doc/view_index.html:49 97 | #, python-format 98 | msgid "" 99 | "View function: <code>%(full_name)s</code>. Name: <code>%(url_name)s</code>." 100 | msgstr "Функция представления: <code>%(full_name)s</code>. Название: <code>%(url_name)s</code>." 101 | 102 | #: templates/includes/carousel.html:4 103 | #: templates/includes/collapsible.html:2 104 | #: templates/includes/horizontal_tabs.html:2 105 | #: templates/includes/vertical_tabs.html:2 106 | msgid "General" 107 | msgstr "Основная информация" 108 | 109 | #: templates/registration/password_change_form.html:28 110 | msgid "" 111 | "Please enter your old password, for security's sake, and then enter your new" 112 | " password twice so we can verify you typed it in correctly." 113 | msgstr "" 114 | "В целях безопасности введите свой старый пароль, а затем дважды введите новый пароль, " 115 | "чтобы мы могли убедиться, что вы ввели его правильно." 116 | 117 | #: templatetags/jazzmin.py:439 118 | #, python-brace-format 119 | msgid "Deleted “{object}”." 120 | msgstr "Удалено “{object}”." 121 | 122 | #: utils.py:74 123 | #, python-brace-format 124 | msgid "Could not reverse url from {instance}" 125 | msgstr "Не удалось получить обратный url для {instance}" 126 | 127 | #: templates/admin/import_export/export.html 128 | msgid "Export" 129 | msgstr "Экспорт" 130 | 131 | #: template/admin/import_export/import.html 132 | msgid "Confirm import" 133 | msgstr "Импорт" 134 | -------------------------------------------------------------------------------- /jazzmin/locale/zh_Hans/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/locale/zh_Hans/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /jazzmin/locale/zh_Hans/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # 2 | msgid "" 3 | msgstr "" 4 | "Project-Id-Version: PACKAGE VERSION\n" 5 | "Report-Msgid-Bugs-To: \n" 6 | "POT-Creation-Date: 2020-10-03 17:04+0100\n" 7 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 8 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 9 | "Language-Team: LANGUAGE <LL@li.org>\n" 10 | "Language: \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Plural-Forms: nplurals=1; plural=0;\n" 15 | 16 | #: templates/admin/base.html:125 17 | msgid "Account" 18 | msgstr "账户" 19 | 20 | #: templates/admin/base.html:143 21 | msgid "See Profile" 22 | msgstr "查看个人资料" 23 | 24 | #: templates/admin/base.html:183 templates/admin/index.html:6 25 | #: templates/admin/index.html:11 26 | msgid "Dashboard" 27 | msgstr "仪表盘" 28 | 29 | #: templates/admin/base.html:294 30 | msgid "Jazzmin version" 31 | msgstr "Jazzmin 版本" 32 | 33 | #: templates/admin/base.html:297 34 | msgid "Copyright" 35 | msgstr "版权" 36 | 37 | #: templates/admin/base.html:297 38 | msgid "All rights reserved." 39 | msgstr "保留所有权利。" 40 | 41 | #: templates/admin/base.html:313 42 | msgid "UI Configuration" 43 | msgstr "UI配置" 44 | 45 | #: templates/admin/base.html:317 46 | msgid "Copy this info your settings file to persist these UI changes" 47 | msgstr "将此信息复制到您的设置文件以保留这些UI更改" 48 | 49 | #: templates/admin/index.html:90 50 | #| msgid "%(entry.action_time|timesince)s ago" 51 | msgid "%(timesince)s ago" 52 | msgstr "%(timesince)s 前" 53 | 54 | #: templates/admin/submit_line.html:8 55 | msgid "Actions" 56 | msgstr "动作" 57 | 58 | #: templates/admin_doc/template_filter_index.html:37 59 | #: templates/admin_doc/view_index.html:43 60 | #, python-format 61 | msgid "" 62 | "View function: <code>%(full_name)s</code>. Name: <code>%(url_name)s</code>." 63 | msgstr "查看函数:<code>%(full_name)s</code>. 名字:<code>%(url_name)s</code>。" 64 | 65 | #: templatetags/jazzmin.py:390 66 | #, fuzzy, python-brace-format 67 | msgid "Added {name} “{object}”." 68 | msgstr "添加了 {name}“{object}”。" 69 | 70 | #: templatetags/jazzmin.py:406 71 | #, python-brace-format 72 | msgid "Deleted “{object}”." 73 | msgstr "删除了“{object}”。" 74 | 75 | #: utils.py:66 76 | #, python-brace-format 77 | msgid "Could not reverse url from {instance}" 78 | msgstr "无法从{instance}中反转URL" 79 | -------------------------------------------------------------------------------- /jazzmin/locale/zh_Hant/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/locale/zh_Hant/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /jazzmin/locale/zh_Hant/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # 2 | msgid "" 3 | msgstr "" 4 | "Project-Id-Version: PACKAGE VERSION\n" 5 | "Report-Msgid-Bugs-To: \n" 6 | "POT-Creation-Date: 2020-10-03 17:04+0100\n" 7 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 8 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 9 | "Language-Team: LANGUAGE <LL@li.org>\n" 10 | "Language: \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Plural-Forms: nplurals=1; plural=0;\n" 15 | 16 | #: templates/admin/base.html:125 17 | msgid "Account" 18 | msgstr "帳戶" 19 | 20 | #: templates/admin/base.html:143 21 | msgid "See Profile" 22 | msgstr "查看個人資料" 23 | 24 | #: templates/admin/base.html:183 templates/admin/index.html:6 25 | #: templates/admin/index.html:11 26 | msgid "Dashboard" 27 | msgstr "儀表盤" 28 | 29 | #: templates/admin/base.html:294 30 | msgid "Jazzmin version" 31 | msgstr "Jazzmin 版本" 32 | 33 | #: templates/admin/base.html:297 34 | msgid "Copyright" 35 | msgstr "版權" 36 | 37 | #: templates/admin/base.html:297 38 | msgid "All rights reserved." 39 | msgstr "保留所有權利。" 40 | 41 | #: templates/admin/base.html:313 42 | msgid "UI Configuration" 43 | msgstr "UI配置" 44 | 45 | #: templates/admin/base.html:317 46 | msgid "Copy this info your settings file to persist these UI changes" 47 | msgstr "將此信息複製到您的設置文件以保留這些UI更改" 48 | 49 | #: templates/admin/index.html:90 50 | #| msgid "%(entry.action_time|timesince)s ago" 51 | msgid "%(timesince)s ago" 52 | msgstr "%(timesince)s 前" 53 | 54 | #: templates/admin/submit_line.html:8 55 | msgid "Actions" 56 | msgstr "動作" 57 | 58 | #: templates/admin_doc/template_filter_index.html:37 59 | #: templates/admin_doc/view_index.html:43 60 | #, python-format 61 | msgid "" 62 | "View function: <code>%(full_name)s</code>. Name: <code>%(url_name)s</code>." 63 | msgstr "視圖函式:<code>%(full_name)s</code>,名稱:<code>%(url_name)s</code>。" 64 | 65 | #: templatetags/jazzmin.py:390 66 | #, fuzzy, python-brace-format 67 | msgid "Added {name} “{object}”." 68 | msgstr "{name} “{object}” 已新增。" 69 | 70 | #: templatetags/jazzmin.py:406 71 | #, python-brace-format 72 | msgid "Deleted “{object}”." 73 | msgstr "“{object}” 已刪除。" 74 | 75 | #: utils.py:66 76 | #, python-brace-format 77 | msgid "Could not reverse url from {instance}" 78 | msgstr "無法從{instance}中反轉URL" 79 | -------------------------------------------------------------------------------- /jazzmin/static/admin/js/cancel.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | 4 | $(document).ready(function() { 5 | $('.cancel-link').click(function(e) { 6 | e.preventDefault(); 7 | const parentWindow = window.parent; 8 | if (parentWindow && typeof(parentWindow.dismissRelatedObjectModal) === 'function' && parentWindow !== window) { 9 | parentWindow.dismissRelatedObjectModal(); 10 | } else { 11 | // fallback to default behavior 12 | window.history.back(); 13 | } 14 | return false; 15 | }); 16 | }); 17 | })(django.jQuery); 18 | -------------------------------------------------------------------------------- /jazzmin/static/admin/js/popup_response.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | 'use strict'; 4 | 5 | var windowRef = window; 6 | var windowRefProxy; 7 | var windowName, widgetName; 8 | var openerRef = windowRef.opener; 9 | if (!openerRef) { 10 | // related modal is active 11 | openerRef = windowRef.parent; 12 | windowName = windowRef.name; 13 | widgetName = windowName.replace(/^(change|add|delete|lookup)_/, ''); 14 | windowRefProxy = { 15 | name: widgetName, 16 | location: windowRef.location, 17 | close: function() { 18 | openerRef.dismissRelatedObjectModal(); 19 | } 20 | }; 21 | windowRef = windowRefProxy; 22 | } 23 | 24 | // default django popup_response.js 25 | var initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); 26 | switch (initData.action) { 27 | case 'change': 28 | if (typeof(openerRef.dismissChangeRelatedObjectPopup) === 'function') { 29 | openerRef.dismissChangeRelatedObjectPopup(windowRef, initData.value, initData.obj, initData.new_value); 30 | } 31 | break; 32 | case 'delete': 33 | if (typeof(openerRef.dismissDeleteRelatedObjectPopup) === 'function') { 34 | openerRef.dismissDeleteRelatedObjectPopup(windowRef, initData.value); 35 | } 36 | break; 37 | default: 38 | if (typeof(openerRef.dismissAddRelatedObjectPopup) === 'function') { 39 | openerRef.dismissAddRelatedObjectPopup(windowRef, initData.value, initData.obj); 40 | } 41 | break; 42 | } 43 | 44 | })(); -------------------------------------------------------------------------------- /jazzmin/static/jazzmin/img/calendar-icons.svg: -------------------------------------------------------------------------------- 1 | <svg width="15" height="60" viewBox="0 0 1792 7168" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 2 | <defs> 3 | <g id="previous"> 4 | <path d="M1037 1395l102-102q19-19 19-45t-19-45l-307-307 307-307q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-454 454q-19 19-19 45t19 45l454 454q19 19 45 19t45-19zm627-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 5 | </g> 6 | <g id="next"> 7 | <path d="M845 1395l454-454q19-19 19-45t-19-45l-454-454q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l307 307-307 307q-19 19-19 45t19 45l102 102q19 19 45 19t45-19zm819-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 8 | </g> 9 | </defs> 10 | <use xlink:href="#previous" x="0" y="0" fill="#333333" /> 11 | <use xlink:href="#previous" x="0" y="1792" fill="#000000" /> 12 | <use xlink:href="#next" x="0" y="3584" fill="#333333" /> 13 | <use xlink:href="#next" x="0" y="5376" fill="#000000" /> 14 | </svg> 15 | -------------------------------------------------------------------------------- /jazzmin/static/jazzmin/img/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/jazzmin/img/default.jpg -------------------------------------------------------------------------------- /jazzmin/static/jazzmin/img/icon-calendar.svg: -------------------------------------------------------------------------------- 1 | <svg width="16" height="32" viewBox="0 0 1792 3584" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 2 | <defs> 3 | <g id="icon"> 4 | <path d="M192 1664h288v-288h-288v288zm352 0h320v-288h-320v288zm-352-352h288v-320h-288v320zm352 0h320v-320h-320v320zm-352-384h288v-288h-288v288zm736 736h320v-288h-320v288zm-384-736h320v-288h-320v288zm768 736h288v-288h-288v288zm-384-352h320v-320h-320v320zm-352-864v-288q0-13-9.5-22.5t-22.5-9.5h-64q-13 0-22.5 9.5t-9.5 22.5v288q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5-9.5t9.5-22.5zm736 864h288v-320h-288v320zm-384-384h320v-288h-320v288zm384 0h288v-288h-288v288zm32-480v-288q0-13-9.5-22.5t-22.5-9.5h-64q-13 0-22.5 9.5t-9.5 22.5v288q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5-9.5t9.5-22.5zm384-64v1280q0 52-38 90t-90 38h-1408q-52 0-90-38t-38-90v-1280q0-52 38-90t90-38h128v-96q0-66 47-113t113-47h64q66 0 113 47t47 113v96h384v-96q0-66 47-113t113-47h64q66 0 113 47t47 113v96h128q52 0 90 38t38 90z"/> 5 | </g> 6 | </defs> 7 | <use xlink:href="#icon" x="0" y="0" fill="#447e9b" /> 8 | <use xlink:href="#icon" x="0" y="1792" fill="#003366" /> 9 | </svg> 10 | -------------------------------------------------------------------------------- /jazzmin/static/jazzmin/img/icon-changelink.svg: -------------------------------------------------------------------------------- 1 | <svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> 2 | <path fill="#efb80b" d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /jazzmin/static/jazzmin/img/selector-icons.svg: -------------------------------------------------------------------------------- 1 | <svg width="16" height="192" viewBox="0 0 1792 21504" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 2 | <defs> 3 | <g id="up"> 4 | <path d="M1412 895q0-27-18-45l-362-362-91-91q-18-18-45-18t-45 18l-91 91-362 362q-18 18-18 45t18 45l91 91q18 18 45 18t45-18l189-189v502q0 26 19 45t45 19h128q26 0 45-19t19-45v-502l189 189q19 19 45 19t45-19l91-91q18-18 18-45zm252 1q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 5 | </g> 6 | <g id="down"> 7 | <path d="M1412 897q0-27-18-45l-91-91q-18-18-45-18t-45 18l-189 189v-502q0-26-19-45t-45-19h-128q-26 0-45 19t-19 45v502l-189-189q-19-19-45-19t-45 19l-91 91q-18 18-18 45t18 45l362 362 91 91q18 18 45 18t45-18l91-91 362-362q18-18 18-45zm252-1q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 8 | </g> 9 | <g id="left"> 10 | <path d="M1408 960v-128q0-26-19-45t-45-19h-502l189-189q19-19 19-45t-19-45l-91-91q-18-18-45-18t-45 18l-362 362-91 91q-18 18-18 45t18 45l91 91 362 362q18 18 45 18t45-18l91-91q18-18 18-45t-18-45l-189-189h502q26 0 45-19t19-45zm256-64q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 11 | </g> 12 | <g id="right"> 13 | <path d="M1413 896q0-27-18-45l-91-91-362-362q-18-18-45-18t-45 18l-91 91q-18 18-18 45t18 45l189 189h-502q-26 0-45 19t-19 45v128q0 26 19 45t45 19h502l-189 189q-19 19-19 45t19 45l91 91q18 18 45 18t45-18l362-362 91-91q18-18 18-45zm251 0q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 14 | </g> 15 | <g id="clearall"> 16 | <path transform="translate(336, 336) scale(0.75)" d="M1037 1395l102-102q19-19 19-45t-19-45l-307-307 307-307q19-19 19-45t-19-45l-102-102q-19-19-45-19t-45 19l-454 454q-19 19-19 45t19 45l454 454q19 19 45 19t45-19zm627-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 17 | </g> 18 | <g id="chooseall"> 19 | <path transform="translate(336, 336) scale(0.75)" d="M845 1395l454-454q19-19 19-45t-19-45l-454-454q-19-19-45-19t-45 19l-102 102q-19 19-19 45t19 45l307 307-307 307q-19 19-19 45t19 45l102 102q19 19 45 19t45-19zm819-499q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/> 20 | </g> 21 | </defs> 22 | <use xlink:href="#up" x="0" y="0" fill="#666666" /> 23 | <use xlink:href="#up" x="0" y="1792" fill="#447e9b" /> 24 | <use xlink:href="#down" x="0" y="3584" fill="#666666" /> 25 | <use xlink:href="#down" x="0" y="5376" fill="#447e9b" /> 26 | <use xlink:href="#left" x="0" y="7168" fill="#666666" /> 27 | <use xlink:href="#left" x="0" y="8960" fill="#447e9b" /> 28 | <use xlink:href="#right" x="0" y="10752" fill="#666666" /> 29 | <use xlink:href="#right" x="0" y="12544" fill="#447e9b" /> 30 | <use xlink:href="#clearall" x="0" y="14336" fill="#666666" /> 31 | <use xlink:href="#clearall" x="0" y="16128" fill="#447e9b" /> 32 | <use xlink:href="#chooseall" x="0" y="17920" fill="#666666" /> 33 | <use xlink:href="#chooseall" x="0" y="19712" fill="#447e9b" /> 34 | </svg> 35 | -------------------------------------------------------------------------------- /jazzmin/static/jazzmin/js/change_list.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | 4 | $.fn.search_filters = function () { 5 | $(this).change(function () { 6 | const $field = $(this); 7 | const $option = $field.find('option:selected'); 8 | const select_name = $option.data('name'); 9 | if (select_name) { 10 | $field.attr('name', select_name); 11 | } else { 12 | $field.removeAttr('name'); 13 | } 14 | }); 15 | $(this).trigger('change'); 16 | }; 17 | 18 | function getMinimuInputLength(element) { 19 | return window.filterInputLength[element.data('name')] ?? window.filterInputLengthDefault; 20 | } 21 | 22 | function searchFilters() { 23 | // Make search filters select2 and ensure they work for filtering 24 | const $ele = $('.search-filter'); 25 | $ele.search_filters(); 26 | $ele.each(function () { 27 | const $this = $(this); 28 | $this.select2({ width: '100%', minimumInputLength: getMinimuInputLength($this) }); 29 | }); 30 | 31 | // Use select2 for mptt dropdowns 32 | const $mptt = $('.search-filter-mptt'); 33 | if ($mptt.length) { 34 | $mptt.search_filters(); 35 | $mptt.select2({ 36 | width: '100%', 37 | minimumInputLength: getMinimuInputLength($mptt), 38 | templateResult: function (data) { 39 | // https://stackoverflow.com/questions/30820215/selectable-optgroups-in-select2#30948247 40 | // rewrite templateresult for build tree hierarchy 41 | if (!data.element) { 42 | return data.text; 43 | } 44 | const $element = $(data.element); 45 | let $wrapper = $('<span></span>'); 46 | $wrapper.attr('style', $($element[0]).attr('style')); 47 | $wrapper.text(data.text); 48 | return $wrapper; 49 | }, 50 | }); 51 | } 52 | } 53 | 54 | $(document).ready(function () { 55 | // Ensure all raw_id_fields have the search icon in them 56 | $('.related-lookup').append('<i class="fa fa-search"></i>') 57 | 58 | // Allow for styling of selects 59 | $('.actions select').addClass('form-control').select2({ width: 'element' }); 60 | 61 | searchFilters(); 62 | }); 63 | 64 | })(jQuery); 65 | -------------------------------------------------------------------------------- /jazzmin/static/jazzmin/js/main.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | 4 | function setCookie(key, value) { 5 | const expires = new Date(); 6 | expires.setTime(expires.getTime() + (value * 24 * 60 * 60 * 1000)); 7 | document.cookie = key + '=' + value + ';expires=' + expires.toUTCString() + '; SameSite=Strict;path=/'; 8 | } 9 | 10 | function getCookie(key) { 11 | const keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)'); 12 | return keyValue ? keyValue[2] : null; 13 | } 14 | 15 | function handleMenu() { 16 | $('[data-widget=pushmenu]').bind('click', function () { 17 | const menuClosed = getCookie('jazzy_menu') === 'closed'; 18 | if (!menuClosed) { 19 | setCookie('jazzy_menu', 'closed'); 20 | } else { 21 | setCookie('jazzy_menu', 'open'); 22 | } 23 | }); 24 | } 25 | 26 | 27 | function setActiveLinks() { 28 | /* 29 | Set the currently active menu item based on the current url, or failing that, find the parent 30 | item from the breadcrumbs 31 | */ 32 | const url = window.location.pathname; 33 | const $breadcrumb = $('.breadcrumb a').last(); 34 | const $link = $('a[href="' + url + '"]'); 35 | const $parent_link = $('a[href="' + $breadcrumb.attr('href') + '"]'); 36 | 37 | if ($link.length) { 38 | $link.addClass('active'); 39 | } else if ($parent_link.length) { 40 | $parent_link.addClass('active'); 41 | }; 42 | 43 | const $a_active = $('a.nav-link.active'); 44 | const $main_li_parent = $a_active.closest('li.nav-item.has-treeview'); 45 | const $ul_child = $main_li_parent.children('ul'); 46 | 47 | $ul_child.show(); 48 | $main_li_parent.addClass('menu-is-opening menu-open'); 49 | }; 50 | 51 | $(document).ready(function () { 52 | // Set active status on links 53 | setActiveLinks() 54 | 55 | // When we use the menu, store its state in a cookie to preserve it 56 | handleMenu(); 57 | 58 | // Add minimal changelist styling to templates that we have been unable to override (e.g MPTT) 59 | // Needs to be here and not in change_list.js because this is the only JS we are guaranteed to run 60 | // (as its included in base.html) 61 | const $changeListTable = $('#changelist .results table'); 62 | if ($changeListTable.length && !$changeListTable.hasClass('table table-striped')) { 63 | $changeListTable.addClass('table table-striped'); 64 | }; 65 | }); 66 | 67 | })(jQuery); 68 | -------------------------------------------------------------------------------- /jazzmin/static/jazzmin/plugins/bootstrap-show-modal/bootstrap-show-modal.min.js: -------------------------------------------------------------------------------- 1 | !function(o){"use strict";var s=0;function i(t){for(var e in this.props={title:"",body:"",footer:"",modalClass:"fade",modalDialogClass:"",options:null,onCreate:null,onDispose:null,onSubmit:null},t)this.props[e]=t[e];this.id="bootstrap-show-modal-"+s,s++,this.show()}i.prototype.createContainerElement=function(){var t=this;this.element=document.createElement("div"),this.element.id=this.id,this.element.setAttribute("class","modal "+this.props.modalClass),this.element.setAttribute("tabindex","-1"),this.element.setAttribute("role","dialog"),this.element.setAttribute("aria-labelledby",this.id),this.element.innerHTML='<div class="modal-dialog '+this.props.modalDialogClass+'" role="document"><div class="modal-content"><div class="modal-header"><h5 class="modal-title"></h5><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button></div><div class="modal-body"></div><div class="modal-footer"></div></div></div>',document.body.appendChild(this.element),this.titleElement=this.element.querySelector(".modal-title"),this.bodyElement=this.element.querySelector(".modal-body"),this.footerElement=this.element.querySelector(".modal-footer"),o(this.element).on("hidden.bs.modal",function(){t.dispose()}),this.props.onCreate&&this.props.onCreate(this)},i.prototype.show=function(){this.element?o(this.element).modal("show"):(this.createContainerElement(),this.props.options?o(this.element).modal(this.props.options):o(this.element).modal()),this.props.title?(o(this.titleElement).show(),this.titleElement.innerHTML=this.props.title):o(this.titleElement).hide(),this.props.body?(o(this.bodyElement).show(),this.bodyElement.innerHTML=this.props.body):o(this.bodyElement).hide(),this.props.footer?(o(this.footerElement).show(),this.footerElement.innerHTML=this.props.footer):o(this.footerElement).hide()},i.prototype.hide=function(){o(this.element).modal("hide")},i.prototype.dispose=function(){o(this.element).modal("dispose"),document.body.removeChild(this.element),this.props.onDispose&&this.props.onDispose(this)},o.extend({showModal:function(t){if(t.buttons){var e,o="";for(e in t.buttons){o+='<button type="button" class="btn btn-primary" data-value="'+e+'" data-dismiss="modal">'+t.buttons[e]+"</button>"}t.footer=o}return new i(t)},showAlert:function(t){return t.buttons={OK:"OK"},this.showModal(t)},showConfirm:function(t){return t.footer='<button class="btn btn-secondary btn-false btn-cancel">'+t.textFalse+'</button><button class="btn btn-primary btn-true">'+t.textTrue+"</button>",t.onCreate=function(e){o(e.element).on("click",".btn",function(t){t.preventDefault(),e.hide(),e.props.onSubmit(-1!==t.target.getAttribute("class").indexOf("btn-true"),e)})},this.showModal(t)}})}(jQuery); 2 | -------------------------------------------------------------------------------- /jazzmin/static/vendor/adminlte/img/AdminLTELogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/adminlte/img/AdminLTELogo.png -------------------------------------------------------------------------------- /jazzmin/static/vendor/adminlte/img/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/adminlte/img/icons.png -------------------------------------------------------------------------------- /jazzmin/static/vendor/adminlte/img/user2-160x160.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/adminlte/img/user2-160x160.jpg -------------------------------------------------------------------------------- /jazzmin/static/vendor/fontawesome-free/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/fontawesome-free/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /jazzmin/static/vendor/fontawesome-free/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/fontawesome-free/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /jazzmin/static/vendor/fontawesome-free/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/fontawesome-free/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /jazzmin/static/vendor/fontawesome-free/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/fontawesome-free/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /jazzmin/static/vendor/fontawesome-free/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/fontawesome-free/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /jazzmin/static/vendor/fontawesome-free/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/fontawesome-free/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /jazzmin/static/vendor/fontawesome-free/webfonts/fa-v4compatibility.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/fontawesome-free/webfonts/fa-v4compatibility.ttf -------------------------------------------------------------------------------- /jazzmin/static/vendor/fontawesome-free/webfonts/fa-v4compatibility.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/static/vendor/fontawesome-free/webfonts/fa-v4compatibility.woff2 -------------------------------------------------------------------------------- /jazzmin/templates/admin/actions.html: -------------------------------------------------------------------------------- 1 | {% load i18n jazzmin %} 2 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 3 | 4 | <div class="actions"> 5 | {% block actions %} 6 | {% block actions-form %} 7 | {% for field in action_form %}<label>{{ field }}</label>{% endfor %} 8 | {% endblock %} 9 | {% block actions-submit %} 10 | <button type="submit" class="btn {{ jazzmin_ui.button_classes.primary }}" style="margin-right: 5px; margin-left: 15px;" title="{% trans "Run the selected action" %}" name="index" value="{{ action_index|default:0 }}"> 11 | {% trans "Go" %} 12 | </button> 13 | {% endblock %} 14 | {% block actions-counter %} 15 | {% if actions_selection_counter %} 16 | <span class="action-counter" data-actions-icnt="{{ cl.result_list|length }}">{{ selection_note }}</span> 17 | {% if cl.result_count != cl.result_list|length %} 18 | <span class="all hidden">{{ selection_note_all }}</span> 19 | <span class="question hidden"> 20 | <a href="#" title="{% trans "Click here to select the objects across all pages" %}"> 21 | {% blocktrans with cl.result_count as total_count %}Select all {{ total_count }} {{ module_name }}{% endblocktrans %} 22 | </a> 23 | </span> 24 | <span class="clear" style="display: none;"><a href="#">{% trans "Clear selection" %}</a></span> 25 | {% endif %} 26 | {% endif %} 27 | {% endblock %} 28 | {% endblock %} 29 | </div> 30 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/app_index.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/index.html" %} 2 | {% load i18n %} 3 | 4 | {% block content_title %} {{ app_label|capfirst }} {% endblock %} 5 | 6 | {% block bodyclass %}{{ block.super }} app-{{ app_label }}{% endblock %} 7 | 8 | {% if not is_popup %} 9 | {% block breadcrumbs %} 10 | <ol class="breadcrumb"> 11 | <li class="breadcrumb-item"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li> 12 | <li class="breadcrumb-item">{% for app in app_list %}{{ app.name }}{% endfor %}</li> 13 | </ol> 14 | {% endblock %} 15 | {% endif %} 16 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/auth/user/add_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/change_form.html" %} 2 | {% load i18n %} 3 | 4 | {% block form_top %} 5 | {% if not is_popup %} 6 | <p class="text-center">{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}</p> 7 | {% else %} 8 | <p class="text-center">{% trans "Enter a username and password." %}</p> 9 | {% endif %} 10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/base_site.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/base.html' %} -------------------------------------------------------------------------------- /jazzmin/templates/admin/change_form_object_tools.html: -------------------------------------------------------------------------------- 1 | {% load i18n admin_urls jazzmin %} 2 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 3 | 4 | {% block object-tools-items %} 5 | {% url opts|admin_urlname:'history' original.pk|admin_urlquote as history_url %} 6 | <a class="btn btn-block {{ jazzmin_ui.button_classes.secondary }} btn-sm" href="{% add_preserved_filters history_url %}">{% trans 'History' %}</a> 7 | {% if has_absolute_url %} 8 | <a href="{{ absolute_url }}" class="btn btn-block {{ jazzmin_ui.button_classes.secondary }} btn-sm">{% trans "View on site" %}</a> 9 | {% endif %} 10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/change_list_object_tools.html: -------------------------------------------------------------------------------- 1 | {% load i18n admin_urls jazzmin %} 2 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 3 | 4 | {% block object-tools-items %} 5 | {% if has_add_permission %} 6 | {% url cl.opts|admin_urlname:'add' as add_url %} 7 | <a href="{% add_preserved_filters add_url is_popup to_field %}" class="btn {{ jazzmin_ui.button_classes.success }} float-right"> 8 | <i class="fa fa-plus-circle"></i>   {% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %} 9 | </a> 10 | {% endif %} 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/change_list_results.html: -------------------------------------------------------------------------------- 1 | {% load i18n static jazzmin %} 2 | 3 | {% if result_hidden_fields %} 4 | <div class="hiddenfields"> 5 | {% for item in result_hidden_fields %}{{ item }}{% endfor %} 6 | </div> 7 | {% endif %} 8 | 9 | {% if results %} 10 | <div class="card"> 11 | <div class="card-body table-responsive p-0"> 12 | <table id="result_list" class="table table-striped"> 13 | <thead> 14 | <tr> 15 | {% for header in result_headers %} 16 | <th class="{% header_class header forloop %}" tabindex="0" rowspan="1" colspan="1"> 17 | <div class="text"> 18 | {% if header.sortable %} 19 | <a href="{{ header.url_primary }}">{{ header.text|capfirst }}</a> 20 | {% else %} 21 | <span>{{ header.text|capfirst }}</span> 22 | {% endif %} 23 | {% if header.sorted %} 24 | <a href="{{ header.url_remove }}"> 25 | <div style="margin-top: .2em;" class="fa fa-times float-right"> </div> 26 | </a> 27 | {% if header.ascending %} 28 | <i style="margin-top: .2em;" class="fa fa-sort-alpha-down"> </i> 29 | {% else %} 30 | <i style="margin-top: .2em;" class="fa fa-sort-alpha-up"> </i> 31 | {% endif %} 32 | {% endif %} 33 | </div> 34 | </th> 35 | {% endfor %} 36 | </tr> 37 | </thead> 38 | <tbody> 39 | {% for result in results %} 40 | <tr role="row" class="{% cycle 'even' 'odd' %}"> 41 | {% for item in result %}{{ item }}{% endfor %} 42 | </tr> 43 | {% endfor %} 44 | </tbody> 45 | </table> 46 | </div> 47 | </div> 48 | {% endif %} 49 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/date_hierarchy.html: -------------------------------------------------------------------------------- 1 | {% load jazzmin %} 2 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 3 | 4 | {% if show %} 5 | <div class="col-12 pb-4" id="change-list-date-hierarchy"> 6 | <div class="btn-group date-hierarchy text-sm"> 7 | {% block date-hierarchy-toplinks %} 8 | {% block date-hierarchy-back %} 9 | {% if back %} 10 | <a class="btn {{ jazzmin_ui.button_classes.secondary }}" href="{{ back.link }}">‹ {{ back.title }}</a> 11 | {% endif %} 12 | {% endblock %} 13 | {% block date-hierarchy-choices %} 14 | {% for choice in choices %} 15 | <a {% if choice.link %}href="{{ choice.link }}" class="btn {{ jazzmin_ui.button_classes.primary }}"{% else %}class="btn {{ jazzmin_ui.button_classes.primary }} active"{% endif %}> 16 | {{ choice.title }} 17 | </a> 18 | {% endfor %} 19 | {% endblock %} 20 | {% endblock %} 21 | </div> 22 | </div> 23 | {% endif %} 24 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/delete_confirmation.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n admin_urls static jazzmin %} 3 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 4 | 5 | {% block extrahead %} 6 | {{ block.super }} 7 | {{ media }} 8 | <script type="text/javascript" src="{% static 'admin/js/cancel.js' %}"></script> 9 | {% endblock %} 10 | 11 | {% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation{% endblock %} 12 | 13 | {% block breadcrumbs %} 14 | <ol class="breadcrumb"> 15 | <li class="breadcrumb-item"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li> 16 | <li class="breadcrumb-item"><a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a></li> 17 | <li class="breadcrumb-item"><a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a></li> 18 | <li class="breadcrumb-item"><a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a></li> 19 | <li class="breadcrumb-item active">{% trans 'Delete' %}</li> 20 | </ol> 21 | {% endblock %} 22 | 23 | {% block content_title %} {% trans 'Delete' %} {% endblock %} 24 | 25 | {% block content %} 26 | 27 | <div class="col-12"> 28 | <div class="card card-danger card-outline"> 29 | <div class="card-header with-border"> 30 | <h4 class="card-title"> 31 | {% trans 'Delete' %} {{ object|truncatewords:"18" }} 32 | </h4> 33 | </div> 34 | 35 | <div class="card-body"> 36 | <div id="content-main"> 37 | {% if perms_lacking %} 38 | <p>{% blocktrans with escaped_object=object %}Deleting the {{ object_name }} '{{ escaped_object }}' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktrans %}</p> 39 | <ol> 40 | {% for obj in perms_lacking %} 41 | <li>{{ obj }}</li> 42 | {% endfor %} 43 | </ol> 44 | {% elif protected %} 45 | <p>{% blocktrans with escaped_object=object %}Deleting the {{ object_name }} '{{ escaped_object }}' would require deleting the following protected related objects:{% endblocktrans %}</p> 46 | <ol> 47 | {% for obj in protected %} 48 | <li>{{ obj }}</li> 49 | {% endfor %} 50 | </ol> 51 | {% else %} 52 | <p>{% blocktrans with escaped_object=object %}Are you sure you want to delete the {{ object_name }} "{{ escaped_object }}"? All of the following related items will be deleted:{% endblocktrans %}</p> 53 | <div class="row"> 54 | <div class="col-12 col-sm-9"> 55 | <h4>{% trans "Objects" %}</h4> 56 | <ol>{{ deleted_objects|unordered_list }}</ol> 57 | </div> 58 | <div class="col-12 col-sm-3"> 59 | {% include "admin/includes/object_delete_summary.html" %} 60 | <form method="post">{% csrf_token %} 61 | <input type="hidden" name="post" value="yes"> 62 | {% if is_popup %}<input type="hidden" name="{{ is_popup_var }}" value="1">{% endif %} 63 | {% if to_field %}<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">{% endif %} 64 | <div class="form-group"> 65 | <input type="submit" class="btn {{ jazzmin_ui.button_classes.danger }} form-control" value="{% trans 'Yes, I’m sure' %}"> 66 | </div> 67 | <div class="form-group"> 68 | <a href="#" class="btn {{ jazzmin_ui.button_classes.danger }} cancel-link form-control">{% trans "No, take me back" %}</a> 69 | </div> 70 | </form> 71 | </div> 72 | </div> 73 | {% endif %} 74 | </div> 75 | </div> 76 | </div> 77 | </div> 78 | 79 | {% endblock %} 80 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/edit_inline/stacked.html: -------------------------------------------------------------------------------- 1 | {% load i18n admin_urls static %} 2 | <div class="js-inline-admin-formset inline-group" id="{{ inline_admin_formset.formset.prefix }}-group" data-inline-type="stacked" data-inline-formset="{{ inline_admin_formset.inline_formset_data }}"> 3 | <fieldset class="module {{ inline_admin_formset.classes }} card card-outline"> 4 | <div class="card-body"> 5 | {{ inline_admin_formset.formset.management_form }} 6 | {{ inline_admin_formset.formset.non_form_errors }} 7 | 8 | {% for inline_admin_form in inline_admin_formset %} 9 | <div class="panel inline-related{% if inline_admin_form.original or inline_admin_form.show_url %} has_original{% endif %}{% if forloop.last and inline_admin_formset.has_add_permission %} empty-form last-related{% endif %}" 10 | id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}"> 11 | <div class="card card-outline {% if not inline_admin_form.original %}new-stacked card-success{% else %}card-secondary{% endif %}"> 12 | <div class="card-header"> 13 | <h3 class="card-title"> 14 | <span class="card-tools text-sm"> 15 | {% if inline_admin_form.original %} 16 | {% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} 17 | <a 18 | href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" 19 | class="{% if inline_admin_formset.has_change_permission %}inlinechangelink{% else %}inlineviewlink{% endif %}"> 20 | {% if inline_admin_formset.has_change_permission %} 21 | <i class="fas fa-pencil-alt fa-sm"> </i> 22 | {% else %} 23 | <i class="fas fa-eye fa-sm"> </i> 24 | {% endif %} 25 | </a> 26 | {% endif %} 27 | {{ inline_admin_form.original }} 28 | {% else %} 29 | <i class="fas fa-plus fa-sm text-success"> </i> 30 | {% trans "New" %} {{ inline_admin_formset.opts.verbose_name|capfirst }} 31 | {% endif %} 32 | </span> 33 | {% if inline_admin_form.show_url %} 34 | <a href="{{ inline_admin_form.absolute_url }}" title="{% trans "View on site" %}"> 35 | <i class="fas fa-eye fa-sm"> </i> 36 | </a> 37 | {% endif %} 38 | </h3> 39 | {% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission and inline_admin_form.original %} 40 | <span class="card-tools delete"> 41 | {{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }} 42 | </span> 43 | {% endif %} 44 | </div> 45 | <div class="card-body"> 46 | {% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %} 47 | {% for fieldset in inline_admin_form %} 48 | {% include "admin/includes/fieldset.html" %} 49 | {% endfor %} 50 | {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} 51 | {% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %} 52 | </div> 53 | </div> 54 | </div> 55 | {% endfor %} 56 | </div> 57 | </fieldset> 58 | </div> 59 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/filer/breadcrumbs.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | <ol class="breadcrumb"> 4 | <li class="breadcrumb-item"><a href="{% url 'admin:index' %}" title="{% trans 'Go back to admin homepage' %}"><i class="fas fa-tachometer-alt"></i> {% trans 'Home' %}</a></li> 5 | <li class="breadcrumb-item"><a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a></li> 6 | {% if not instance.is_root and instance.is_smart_folder %} 7 | <li class="breadcrumb-item"> 8 | <a href="{% url 'admin:filer-directory_listing-root' %}" title="{% trans 'Go back to root folder' %}">{% trans "root" %}</a> 9 | </li> 10 | {% endif %} 11 | {% for ancestor_folder in instance.logical_path %} 12 | <li class="breadcrumb-item"> 13 | <a href="{{ ancestor_folder.get_admin_directory_listing_url_path }}" title="{% blocktrans with ancestor_folder.name as folder_name %}Go back to '{{ folder_name }}' folder{% endblocktrans %}"> 14 | {% if ancestor_folder.label %} 15 | {{ ancestor_folder.label }} 16 | {% else %} 17 | {{ ancestor_folder.name }} 18 | {% endif %} 19 | </a> 20 | </li> 21 | {% endfor %} 22 | {% if breadcrumbs_action %} 23 | <li class="breadcrumb-item">{% if instance.label or instance.name %} 24 | <a href="{{ instance.get_admin_directory_listing_url_path }}" title="{% blocktrans with instance.name as folder_name %}Go back to '{{ folder_name }}' folder{% endblocktrans %}">{% if instance.label %}{{ instance.label }}{% else %}{{ instance.name }}{% endif %}</a></li> 25 | {% endif %} 26 | <li class="breadcrumb-item active">{{ breadcrumbs_action }}</li> 27 | {% else %} 28 | <li class="breadcrumb-item active">{% if instance.label %}{{ instance.label }}{% else %}{{ instance.name }}{% endif %}</li> 29 | {% endif %} 30 | </ol> 31 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/filer/change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/change_form.html" %} 2 | {% load i18n admin_modify static filer_admin_tags %} 3 | 4 | {% block breadcrumbs %} 5 | {% with original as instance %} 6 | {% include "admin/filer/breadcrumbs.html" %} 7 | {% endwith %} 8 | {% endblock %} 9 | 10 | {% block extrastyle %} 11 | {{ block.super }} 12 | <link rel="stylesheet" type="text/css" href="{% static 'filer/css/admin_filer.css' %}"> 13 | {% endblock %} 14 | 15 | 16 | {% block after_field_sets %} 17 | {% filer_admin_context_hidden_formfields %} 18 | {% endblock %} 19 | 20 | {% block file_sidebar %} 21 | {% with original.duplicates as duplicates %} 22 | {% if duplicates %} 23 | <div class="file-duplicates"> 24 | <h3>{% trans "Duplicates" %}</h3> 25 | <ul> 26 | {% for duplicate in duplicates %} 27 | <li><a href="{{ duplicate.get_admin_change_url }}">{{ duplicate }}</a></li> 28 | {% endfor %} 29 | </ul> 30 | </div> 31 | {% endif %} 32 | {% endwith %} 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/filer/delete_selected_files_confirmation.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/delete_selected_confirmation.html" %} 2 | {% load i18n static admin_urls static jazzmin %} 3 | 4 | {% block breadcrumbs %} 5 | {% include "admin/filer/breadcrumbs.html" %} 6 | {% endblock %} 7 | 8 | {% block content %} 9 | <div class="col-12"> 10 | <div class="card card-danger card-outline"> 11 | <div class="card-header with-border"> 12 | <h4 class="card-title"> 13 | {% trans 'Delete multiple objects' %} 14 | </h4> 15 | </div> 16 | 17 | <div class="card-body"> 18 | <div id="content-main"> 19 | 20 | {% if perms_lacking or protected %} 21 | {% if perms_lacking %} 22 | <p>{% blocktrans %}Deleting the selected files and/or folders would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktrans %}</p> 23 | <ol> 24 | {% for obj in perms_lacking %} 25 | <li>{{ obj }}</li> 26 | {% endfor %} 27 | </ol> 28 | {% endif %} 29 | {% if protected %} 30 | <p>{% blocktrans %}Deleting the selected files and/or folders would require deleting the following protected related objects:{% endblocktrans %}</p> 31 | <ol> 32 | {% for obj in protected %} 33 | <li>{{ obj }}</li> 34 | {% endfor %} 35 | </ol> 36 | {% endif %} 37 | {% else %} 38 | <p>{% blocktrans %}Are you sure you want to delete the selected files and/or folders? All of the following objects and their related items will be deleted:{% endblocktrans %}</p> 39 | <div class="row"> 40 | <div class="col-12 col-sm-9"> 41 | <h4>{% trans "Objects" %}</h4> 42 | {% for deletable_object in deletable_objects %} 43 | <ol>{{ deletable_object|unordered_list }}</ol> 44 | {% endfor %} 45 | </div> 46 | <div class="col-12 col-sm-3"> 47 | <form action="" method="post"> 48 | {% csrf_token %} 49 | {% for f in files_queryset %} 50 | <input type="hidden" name="{{ action_checkbox_name }}" value="file-{{ f.pk }}"> 51 | {% endfor %} 52 | {% for f in folders_queryset %} 53 | <input type="hidden" name="{{ action_checkbox_name }}" value="folder-{{ f.pk }}"> 54 | {% endfor %} 55 | {% if is_popup %} 56 | <input type="hidden" name="_popup" value="1"> 57 | {% if select_folder %}<input type="hidden" name="select_folder" value="1">{% endif %} 58 | {% endif %} 59 | <input type="hidden" name="action" value="delete_files_or_folders"> 60 | <input type="hidden" name="post" value="yes"> 61 | <div class="form-group"> 62 | <input type="submit" class="btn {{ jazzmin_ui.button_classes.danger }} form-control" value="{% trans 'Yes, I’m sure' %}"> 63 | </div> 64 | <div class="form-group"> 65 | <a href="#" onclick="window.history.back(); return false;" class="btn {{ jazzmin_ui.button_classes.danger }} cancel-link form-control">{% trans "No, take me back" %}</a> 66 | </div> 67 | </form> 68 | </div> 69 | </div> 70 | {% endif %} 71 | </div> 72 | </div> 73 | </div> 74 | </div> 75 | {% endblock %} -------------------------------------------------------------------------------- /jazzmin/templates/admin/filer/file/change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/filer/change_form.html" %} 2 | {% load admin_modify static %} 3 | 4 | {% block extrahead %} 5 | {{ block.super }} 6 | 7 | {# upload stuff #} 8 | <script type="text/javascript"> 9 | var __jQuery = django.jQuery; 10 | window.jQuery = (__jQuery) ? __jQuery : window.jQuery || undefined; 11 | window.$ = window.jQuery; 12 | </script> 13 | <script src="{% static 'filer/js/libs/class.min.js' %}"></script> 14 | <script src="{% static 'filer/js/libs/jquery-ui.min.js' %}"></script> 15 | <script src="{% static 'filer/js/libs/jquery.cookie.min.js' %}"></script> 16 | <script src="{% static 'filer/js/libs/fileuploader.min.js' %}"></script> 17 | <script src="{% static 'filer/js/libs/mediator.min.js' %}"></script> 18 | <script src="{% static 'filer/js/libs/retina.min.js' %}"></script> 19 | <script src="{% static 'admin/js/admin/RelatedObjectLookups.js' %}"></script> 20 | <script src="{% static 'filer/js/addons/popup_handling.js' %}"></script> 21 | <script src="{% static 'filer/js/addons/focal-point.js' %}"></script> 22 | <script src="{% static 'filer/js/addons/toggler.js' %}"></script> 23 | <script src="{% static 'filer/js/base.js' %}"></script> 24 | <script type="text/javascript"> 25 | var __jQuery; 26 | var __$; 27 | // reassign jQuery if jQuery is already loaded 28 | __jQuery = (window.jQuery) ? window.jQuery.noConflict(true) : undefined; 29 | __$ = __jQuery; 30 | </script> 31 | {% endblock %} 32 | 33 | {% block submit_buttons_bottom %} 34 | {% include "admin/filer/tools/detail_info.html" with file=True %} 35 | {{ block.super }} 36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/filer/folder/change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/change_form.html" %} 2 | {% load i18n admin_modify static filer_admin_tags %} 3 | 4 | {% block breadcrumbs %} 5 | <ol class="breadcrumb"> 6 | <li class="breadcrumb-item"><a href="{% url 'admin:index' %}" title="{% trans 'Go back to admin homepage' %}"><i class="fas fa-tachometer-alt"></i> {% trans 'Home' %}</a></li> 7 | <li class="breadcrumb-item"><a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a></li> 8 | <li class="breadcrumb-item"> 9 | <a href="{% url 'admin:filer-directory_listing-root' %}" title="{% trans 'Go back to' %} '{% trans 'root'|title %}' {% trans 'folder' %}">{% trans "root"|title %}</a> 10 | </li> 11 | {% for ancestor_folder in original.get_ancestors %} 12 | <li class="breadcrumb-item"> 13 | <a href="{% url 'admin:filer-directory_listing' ancestor_folder.id %}" title="{% blocktrans with ancestor_folder.name as folder_name %}Go back to '{{ folder_name }}' folder{% endblocktrans %}">{{ ancestor_folder.name }}</a> 14 | </li> 15 | {% endfor %} 16 | <li class="breadcrumb-item active">{{ original.name }}</li> 17 | </ol> 18 | {% endblock %} 19 | 20 | {% block coltype %}{% if is_popup %}colM{% else %}colMS{% endif %}{% endblock %} 21 | 22 | {% block object-tools %} 23 | {% if change and not is_popup %} 24 | <a class="btn btn-block {{ jazzmin_ui.button_classes.secondary }} btn-sm" href="{% url history_url object_id %}">{% trans 'History' %}</a> 25 | {% if has_absolute_url %} 26 | <a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="btn btn-block {{ jazzmin_ui.button_classes.secondary }} btn-sm">{% trans "View on site" %}</a> 27 | {% endif%} 28 | {% endif %} 29 | {% endblock %} 30 | 31 | {% block after_field_sets %} 32 | {% filer_admin_context_hidden_formfields %} 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/filer/image/change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/filer/change_form.html" %} 2 | {% load admin_modify static %} 3 | 4 | {% block extrahead %} 5 | {{ block.super }} 6 | 7 | {# upload stuff #} 8 | <script type="text/javascript"> 9 | var __jQuery = django.jQuery; 10 | window.jQuery = (__jQuery) ? __jQuery : window.jQuery || undefined; 11 | window.$ = window.jQuery; 12 | </script> 13 | <script src="{% static 'filer/js/libs/class.min.js' %}"></script> 14 | <script src="{% static 'filer/js/libs/jquery-ui.min.js' %}"></script> 15 | <script src="{% static 'filer/js/libs/jquery.cookie.min.js' %}"></script> 16 | <script src="{% static 'filer/js/libs/fileuploader.min.js' %}"></script> 17 | <script src="{% static 'filer/js/libs/mediator.min.js' %}"></script> 18 | <script src="{% static 'filer/js/libs/retina.min.js' %}"></script> 19 | <script src="{% static 'admin/js/admin/RelatedObjectLookups.js' %}"></script> 20 | <script src="{% static 'filer/js/addons/popup_handling.js' %}"></script> 21 | <script src="{% static 'filer/js/addons/focal-point.js' %}"></script> 22 | <script src="{% static 'filer/js/addons/toggler.js' %}"></script> 23 | <script src="{% static 'filer/js/base.js' %}"></script> 24 | <script type="text/javascript"> 25 | var __jQuery; 26 | var __$; 27 | // reassign jQuery if jQuery is already loaded 28 | __jQuery = (window.jQuery) ? window.jQuery.noConflict(true) : undefined; 29 | __$ = __jQuery; 30 | </script> 31 | {% endblock %} 32 | 33 | {% block submit_buttons_bottom %} 34 | {% include "admin/filer/tools/detail_info.html" %} 35 | {{ block.super }} 36 | {% endblock %} -------------------------------------------------------------------------------- /jazzmin/templates/admin/filer/tools/detail_info.html: -------------------------------------------------------------------------------- 1 | {% load filer_admin_tags i18n static jazzmin %} 2 | 3 | <div class="card"> 4 | <div class="card-header"> 5 | <h3 class="card-title"> 6 | <span class="icon fa fa-file{% if original.file_type == 'Image' %}-image-o{% endif %}"></span> 7 | {{ original }} 8 | </h3> 9 | </div> 10 | <div class="card-body"> 11 | <div class="image-preview-container"> 12 | {% if file %} 13 | <img src="{% if original.icons.48 %}{{ original.icons.48 }}{% else %}{% static 'filer/icons/missingfile_48x48.png' %}{% endif %}"> 14 | {% else %} 15 | <div class="image-preview js-focal-point" data-location-selector="#id_subject_location"> 16 | <img src="{{ original.thumbnails.admin_sidebar_preview }}" data-ratio="{{ adminform.form.sidebar_image_ratio }}" class="js-focal-point-image"> 17 | <div class="image-preview-field"> 18 | <div class="js-focal-point-circle image-preview-circle hidden"></div> 19 | </div> 20 | </div> 21 | {% endif %} 22 | </div> 23 | {% if original.file_type or original.modified_at or original.uploaded_at or original.width or original.height or original.size or original.owner %} 24 | <ul> 25 | {% if original.file_type %} 26 | <li><b>{% trans "Type" %}</b>: {{ original.extension|upper }} {{ original.file_type }}</li> 27 | {% endif %} 28 | {% if original.width or original.height %} 29 | <li><b>{% trans "Size" %}</b>: {{ original.width }}x{{ original.height }} px</li> 30 | {% endif %} 31 | {% if original.size %} 32 | <li><b>{% trans "File-size" %}</b>: {{ original.size|filesizeformat }}</li> 33 | {% endif %} 34 | {% if original.modified_at %} 35 | <li><b>{% trans "Modified" %}</b>: {{ original.modified_at }}</li> 36 | {% endif %} 37 | {% if original.uploaded_at %} 38 | <li><b>{% trans "Created" %}</b>: {{ original.uploaded_at }}</li> 39 | {% endif %} 40 | {% if original.owner %} 41 | <li><b>{% trans "Owner" %}</b>: <span class="icon fa fa-user"></span> {{ original.owner }}</li> 42 | {% endif %} 43 | </ul> 44 | {% endif %} 45 | <div class="text-center"> 46 | <a href="{{ original.url }}" target="_blank" class="btn {{ jazzmin_ui.button_classes.info }} form-control" download="{{ original.original_filename }}"> 47 | {% if file %} 48 | {% trans "Open file" %} 49 | {% else %} 50 | {% trans "Full size preview" %} 51 | {% endif %} 52 | </a> 53 | </div> 54 | </div> 55 | </div> 56 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/filter.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | <div class="form-group"> 4 | <select class="form-control search-filter" style="width: 100%;" tabindex="-1" aria-hidden="true" data-name="{{ field_name }}"> 5 | <option value="">{{ title }}</option> 6 | <option value="">---------</option> 7 | {% for choice in choices %} 8 | {% if choice.name %} 9 | <option data-name="{{ choice.name }}" value="{{ choice.value }}" {% if choice.selected %}selected {% endif %}> 10 | {{ choice.display }} 11 | </option> 12 | {% endif %} 13 | {% endfor %} 14 | </select> 15 | </div> 16 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/import_export/base.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n admin_modify %} 3 | {% load admin_urls %} 4 | {% load static %} 5 | 6 | {% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %} 7 | {% block bodyclass %}{{ block.super }} {{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %} 8 | {% if not is_popup %} 9 | {% block breadcrumbs %} 10 | 11 | <ol class="breadcrumb"> 12 | <li class="breadcrumb-item"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li> 13 | <li class="breadcrumb-item"><a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a></li> 14 | <li class="breadcrumb-item"><a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a></li> 15 | <li class="breadcrumb-item active">{% block breadcrumbs_last %}{% endblock %}</li> 16 | </ol> 17 | 18 | {% endblock %} 19 | {% endif %} 20 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/import_export/change_list.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/change_list.html" %} 2 | 3 | {# Original template renders object-tools only when has_add_permission is True. #} 4 | {# This hack allows sub templates to add to object-tools #} 5 | {% block object-tools %} 6 | <ul class="object-tools"> 7 | {% block object-tools-items %} 8 | {% if has_add_permission %} 9 | {{ block.super }} 10 | {% endif %} 11 | {% endblock %} 12 | </ul> 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/import_export/change_list_export.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/import_export/change_list.html" %} 2 | 3 | {% block object-tools-items %} 4 | {% include "admin/import_export/change_list_export_item.html" %} 5 | {{ block.super }} 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/import_export/change_list_export_item.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load admin_urls %} 3 | 4 | {% if has_export_permission %} 5 | <a href="{% url opts|admin_urlname:'export' %}{{cl.get_query_string}}" class="export_link btn {{ jazzmin_ui.button_classes.secondary }}"> 6 | <i class="fas fa-file-export"></i> {% trans "Export" %} 7 | </a> 8 | {% endif %} 9 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/import_export/change_list_import.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/import_export/change_list.html" %} 2 | 3 | {% block object-tools-items %} 4 | {% include "admin/import_export/change_list_import_item.html" %} 5 | {{ block.super }} 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/import_export/change_list_import_export.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/import_export/change_list.html" %} 2 | 3 | {% block object-tools-items %} 4 | <div class="btn-group float-right"> 5 | {% include "admin/import_export/change_list_import_item.html" %} 6 | {% include "admin/import_export/change_list_export_item.html" %} 7 | {{ block.super }} 8 | </div> 9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/import_export/change_list_import_item.html: -------------------------------------------------------------------------------- 1 | {% load i18n admin_urls jazzmin %} 2 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 3 | 4 | {% if has_import_permission %} 5 | <a href='{% url opts|admin_urlname:"import" %}' class="import_link btn {{ jazzmin_ui.button_classes.secondary }}"> 6 | <i class="fas fa-file-import"></i> {% trans "Import" %} 7 | </a> 8 | {% endif %} 9 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/import_export/export.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/import_export/base.html" %} 2 | {% load i18n admin_urls static import_export_tags jazzmin %} 3 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 4 | 5 | {% block extrastyle %} 6 | {{ block.super }} 7 | <link rel="stylesheet" href="{% static 'vendor/select2/css/select2.min.css' %}"> 8 | {% endblock %} 9 | 10 | {% block breadcrumbs_last %} 11 | {% trans "Export" %} 12 | {% endblock %} 13 | 14 | {% block content %} 15 | <div class="col-12"> 16 | <form action="" method="POST" class="form-horizontal"> 17 | {% csrf_token %} 18 | <div class="row"> 19 | <div class="col-12 col-lg-9"> 20 | <div class="card"> 21 | <div class="card-header"> 22 | <div class="card-title"> 23 | Export 24 | </div> 25 | </div> 26 | <div class="card-body"> 27 | {% for field in form %} 28 | <div class="form-group field-name"> 29 | <div class="row"> 30 | {{ field.errors }} 31 | <div class="col-sm-2 text-left"> 32 | {{ field.label_tag }} 33 | </div> 34 | <div class="col-sm-10 text-left"> 35 | {{ field }} 36 | </div> 37 | 38 | <div class="help-block red"> 39 | {% if field.field.help_text %} 40 | <img src="{% static "admin/img/icon-unknown.svg" %}" class="help help-tooltip" width="10" height="10" alt="({{ field.field.help_text|striptags }})" title="{{ field.field.help_text|striptags }}"> 41 | {% endif %} 42 | </div> 43 | </div> 44 | </div> 45 | {% endfor %} 46 | </div> 47 | </div> 48 | </div> 49 | 50 | <div class="col-12 col-lg-3"> 51 | <div class="card"> 52 | <div class="card-header"> 53 | <h3 class="card-title"> 54 | <i class="fas fa-edit"></i> 55 | Actions 56 | </h3> 57 | </div> 58 | <div class="card-body"> 59 | <div class="form-group"> 60 | <input type="submit" class="btn {{ jazzmin_ui.button_classes.success }} form-control" value="{% trans "Submit" %}"> 61 | </div> 62 | </div> 63 | </div> 64 | </div> 65 | </div> 66 | </form> 67 | </div> 68 | {% endblock %} 69 | 70 | {% block extrajs %} 71 | {{ block.super }} 72 | <script type="text/javascript" src="{% static 'vendor/select2/js/select2.min.js' %}"></script> 73 | <script type="text/javascript" src="{% static 'jazzmin/js/change_form.js' %}"></script> 74 | {% endblock %} 75 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/includes/fieldset.html: -------------------------------------------------------------------------------- 1 | {% load jazzmin %} 2 | {% if card %} 3 | <div class="card {{ fieldset.classes|cut:"collapse" }}"> 4 | {% if card_header and fieldset.name %} 5 | <div class="card-header"> 6 | <div class="card-title"> 7 | <strong>{{ fieldset.name }}</strong>{% if fieldset.description %} - <i>{{ fieldset.description }}</i>{% endif %} 8 | </div> 9 | </div> 10 | {%elif fieldset.description %} 11 | <div class="card-header"> 12 | <div class="card-title"> 13 | {{ fieldset.description }} 14 | </div> 15 | </div> 16 | {%endif%} 17 | 18 | <div class="p-5{% if fieldset.name %} card-body{% endif %}"> 19 | {% endif %} 20 | 21 | {% for line in fieldset %} 22 | <div class="form-group{% if line.fields|length == 1 and line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}"> 23 | <div class="row"> 24 | {% for field in line %} 25 | <label class="{% if not line.fields|length == 1 and forloop.counter != 1 %}col-auto {% else %}col-sm-3 {% endif %}text-left" for="id_{{ field.field.name }}"> 26 | {{ field.field.label|capfirst }} 27 | {% if field.field.field.required %} 28 | <span class="text-red">* </span> 29 | {% endif %} 30 | </label> 31 | <div class="{% if not line.fields|length == 1 %} col-auto fieldBox {% else %} col-sm-9 {% endif %} 32 | {% if field.field.name %} field-{{ field.field.name }}{% endif %} 33 | {% if not field.is_readonly and field.errors %} errors{% endif %} 34 | {% if field.field.is_hidden %} hidden {% endif %} 35 | {% if field.is_checkcard %} checkcard-row{% endif %}"> 36 | {% if field.is_readonly %} 37 | <div class="readonly">{{ field.contents }}</div> 38 | {% else %} 39 | {{ field.field }} 40 | {% endif %} 41 | <div class="help-block red"> 42 | {% if not line.fields|length == 1 and not field.is_readonly %}{{ field.errors }}{% endif %} 43 | </div> 44 | {% if field.field.help_text %} 45 | <div class="help-block">{{ field.field.help_text|safe }}</div> 46 | {% endif %} 47 | <div class="help-block text-red"> 48 | {% if line.fields|length == 1 %}{{ line.errors }}{% endif %} 49 | </div> 50 | </div> 51 | {% endfor %} 52 | </div> 53 | </div> 54 | {% endfor %} 55 | 56 | {% if card %} 57 | </div> 58 | </div> 59 | {% endif %} 60 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/includes/object_delete_summary.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | <h4>{% trans "Summary" %}</h4> 3 | <table class="table table-striped"> 4 | <tbody> 5 | {% for model_name, object_count in model_count %} 6 | <tr> 7 | <td>{{ model_name|capfirst }}</td> 8 | <td>{{ object_count }}</td> 9 | </tr> 10 | {% endfor %} 11 | </tbody> 12 | </table> 13 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/login.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | 3 | {% load i18n jazzmin %} 4 | {% get_jazzmin_settings request as jazzmin_settings %} 5 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 6 | 7 | {% block content %} 8 | <p class="login-box-msg">{{ jazzmin_settings.welcome_sign }}</p> 9 | <form action="{{ app_path }}" method="post"> 10 | {% csrf_token %} 11 | {% if user.is_authenticated %} 12 | <p class="errornote"> 13 | <div class="callout callout-danger"> 14 | <p> 15 | {% blocktrans trimmed %} 16 | You are authenticated as {{ username }}, but are not authorized to 17 | access this page. Would you like to login to a different account? 18 | {% endblocktrans %} 19 | </p> 20 | </div> 21 | </p> 22 | {% endif %} 23 | {% if form.errors %} 24 | {% if form.username.errors %} 25 | <div class="callout callout-danger"> 26 | <p>{{ form.username.label }}: {{ form.username.errors|join:', ' }}</p> 27 | </div> 28 | {% endif %} 29 | {% if form.password.errors %} 30 | <div class="callout callout-danger"> 31 | <p>{{ form.password.label }}: {{ form.password.errors|join:', ' }}</p> 32 | </div> 33 | {% endif %} 34 | {% if form.non_field_errors %} 35 | <div class="callout callout-danger"> 36 | {% for error in form.non_field_errors %} 37 | <p>{{ error }}</p> 38 | {% endfor %} 39 | </div> 40 | {% endif %} 41 | {% endif %} 42 | <div class="input-group mb-3"> 43 | <input type="text" name="username" class="form-control" placeholder="{{ form.username.label }}" required> 44 | <div class="input-group-append"> 45 | <div class="input-group-text"> 46 | <span class="fas fa-user"></span> 47 | </div> 48 | </div> 49 | </div> 50 | <div class="input-group mb-3"> 51 | <input type="password" name="password" class="form-control" placeholder="{{ form.password.label }}" required> 52 | <div class="input-group-append"> 53 | <div class="input-group-text"> 54 | <span class="fas fa-lock"></span> 55 | </div> 56 | </div> 57 | </div> 58 | {% url 'admin_password_reset' as password_reset_url %} 59 | {% if password_reset_url %} 60 | <div class="mb-3"> 61 | <div class="password-reset-link" style="text-align: center;"> 62 | <a href="{{ password_reset_url }}"> 63 | {% trans 'Forgotten your password or username?' %} 64 | </a> 65 | </div> 66 | </div> 67 | {% endif %} 68 | <div class="row"> 69 | <div class="col-12"> 70 | <button type="submit" class="btn {{ jazzmin_ui.button_classes.primary }} btn-block"> 71 | {% trans "Log in" %} 72 | </button> 73 | </div> 74 | </div> 75 | </form> 76 | {% endblock %} 77 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/mptt_filter.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load mptt_admin %} 3 | 4 | <div class="form-group"> 5 | <select class="form-control search-filter-mptt" style="width: 100%;" tabindex="-1" aria-hidden="true" data-name="{{ field_name }}"> 6 | <option value="">{{ title }}</option> 7 | <option value="">---------</option> 8 | {% for choice in choices %} 9 | {% if choice.name %} 10 | <option {{ choice.padding_style }} data-name="{{ choice.name }}" value="{{ choice.value }}" {% if choice.selected %}selected {% endif %}> 11 | {{ choice.display }} 12 | </option> 13 | {% endif %} 14 | {% endfor %} 15 | </select> 16 | </div> -------------------------------------------------------------------------------- /jazzmin/templates/admin/object_history.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n admin_urls static jazzmin %} 3 | 4 | {% block breadcrumbs %} 5 | <ol class="breadcrumb"> 6 | <li class="breadcrumb-item"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li> 7 | <li class="breadcrumb-item"><a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a></li> 8 | <li class="breadcrumb-item"><a href="{% url opts|admin_urlname:'changelist' %}">{{ module_name }}</a></li> 9 | <li class="breadcrumb-item"><a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a></li> 10 | <li class="breadcrumb-item active">{% trans 'History' %}</li> 11 | </ol> 12 | {% endblock %} 13 | 14 | {% block content %} 15 | 16 | <div class="row col-md-12"> 17 | <div class="col-12"> 18 | <div class="card"> 19 | <div class="card-header with-border"> 20 | <h4 class="card-title"> 21 | {% trans 'History' %} 22 | </h4> 23 | </div> 24 | 25 | <div class="card-body"> 26 | <div id="content-main"> 27 | <div class="module"> 28 | 29 | <div class="timeline"> 30 | 31 | {% for action in action_list reversed %} 32 | <div class="time-label"> 33 | <span class="bg-info">{{ action.action_time|date:"DATETIME_FORMAT" }}</span> 34 | </div> 35 | 36 | {% action_message_to_list action as action_message_list %} 37 | {% for action_message in action_message_list %} 38 | <div> 39 | <i class="fas fa-{{ action_message.icon }} bg-{{ action_message.colour }}"></i> 40 | <div class="timeline-item"> 41 | <h3 class="timeline-header no-border"> 42 | <a href="{% jazzy_admin_url action.user request.current_app|default:"admin" %}" target="_blank"> 43 | {{ action.user.get_username }}{% if action.user.get_full_name %} ({{ action.user.get_full_name }}){% endif %} 44 | </a> 45 | {{ action_message.msg|style_bold_first_word }} 46 | </h3> 47 | </div> 48 | </div> 49 | {% endfor %} 50 | 51 | {% endfor %} 52 | 53 | <div> 54 | <i class="fas fa-clock bg-gray"></i> 55 | {% if not action_list %} 56 | <div class="timeline-item"> 57 | <h3 class="timeline-header no-border"> 58 | {% trans "This object doesn't have a change history. It probably wasn't added via this admin site." %} 59 | </h3> 60 | </div> 61 | {% endif %} 62 | </div> 63 | </div> 64 | 65 | </div> 66 | </div> 67 | </div> 68 | </div> 69 | </div> 70 | </div> 71 | 72 | {% endblock %} 73 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/pagination.html: -------------------------------------------------------------------------------- 1 | {% load admin_list jazzmin i18n %} 2 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 3 | 4 | <div class="col-5"> 5 | <div class="dataTables_info" role="status" aria-live="polite"> 6 | {{ cl.result_count }} 7 | {% if cl.result_count == 1 %} 8 | {{ cl.opts.verbose_name }} 9 | {% else %} 10 | {{ cl.opts.verbose_name_plural }} 11 | {% endif %} 12 | 13 | {% if show_all_url %}   14 | <a href="{{ show_all_url }}" class="btn btn-sm {{ jazzmin_ui.button_classes.secondary }}">{% trans 'Show all' %}</a> 15 | {% endif %} 16 | {% if cl.formset and cl.result_count %} 17 | <input type="submit" name="_save" class="btn btn-sm {{ jazzmin_ui.button_classes.success }}" value="{% trans 'Save' %}"> 18 | {% endif %} 19 | </div> 20 | </div> 21 | 22 | <div class="col-7"> 23 | <ul class="pagination pagination-sm m-0 float-right"> 24 | {% if pagination_required %} 25 | {% for i in page_range %} 26 | {% jazzmin_paginator_number cl i %} 27 | {% endfor %} 28 | {% endif %} 29 | </ul> 30 | </div> 31 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/popup_response.html: -------------------------------------------------------------------------------- 1 | {% load i18n static %} 2 | 3 | <!DOCTYPE html> 4 | <html> 5 | <head><title>{% trans 'Popup closing...' %} 6 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/search_form.html: -------------------------------------------------------------------------------- 1 | {% load i18n static admin_list jazzmin %} 2 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 3 | 4 |
5 | 43 |
44 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/solo/change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/change_form.html" %} 2 | {% load admin_urls i18n jazzmin %} 3 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 4 | 5 | {% block breadcrumbs %} 6 | 11 | {% endblock %} 12 | 13 | {% block object-tools-items %} 14 | {% trans 'History' %} 15 | {% if has_absolute_url %} 16 | {% trans "View on site" %} 17 | {% endif %} 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/solo/object_history.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/object_history.html" %} 2 | {% load admin_urls i18n %} 3 | 4 | {% block breadcrumbs %} 5 | 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /jazzmin/templates/admin/submit_line.html: -------------------------------------------------------------------------------- 1 | {% load i18n admin_urls jazzmin %} 2 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 3 | 4 | {% block submit-row %} 5 |
6 | {% if show_save %} 7 |
8 | 9 |
10 | {% endif %} 11 | {% if show_delete_link and original %} 12 |
13 | {% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %} 14 | {% trans "Delete" %} 15 |
16 | {% endif %} 17 | {% if show_save_as_new %} 18 |
19 | 20 |
21 | {% endif %} 22 | {% if show_save_and_add_another %} 23 |
24 | 25 |
26 | {% endif %} 27 | {% if show_save_and_continue %} 28 |
29 | 30 |
31 | {% endif %} 32 | {% if show_close %} 33 |
34 | {% trans 'Close' %} 35 |
36 | {% endif %} 37 | 38 | {% block extra-actions %}{% endblock %} 39 | 40 |
41 | {% endblock %} 42 | 43 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/base_docs.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | 3 | {% block extrastyle %} 4 | 5 | 20 | {% endblock %} 21 | 22 | {% block content %} 23 | {% block alerts %}{% endblock %} 24 |
25 |
26 |
27 |
28 | {% block docs_content %}{% endblock %} 29 |
30 |
31 |
32 |
33 | {% endblock %} -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/bookmarklets.html: -------------------------------------------------------------------------------- 1 | {% extends "admin_doc/base_docs.html" %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumbs %} 5 | 10 | {% endblock %} 11 | 12 | {% block title %}{% trans "Documentation bookmarklets" %}{% endblock %} 13 | 14 | {% block alerts %} 15 |
16 | 17 |
Info
18 |

19 | {% blocktrans trimmed %} 20 | To install bookmarklets, drag the link to your bookmarks toolbar, or right-click 21 | the link and add it to your bookmarks. Now you can select the bookmarklet 22 | from any page in the site. 23 | {% endblocktrans %} 24 |

25 |
26 | {% endblock %} 27 | 28 | {% block docs_content %} 29 |
30 |

{% trans "Documentation for this page" %}

31 |

{% trans "Jumps you from any page to the documentation for the view that generates that page." %}

32 |
33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/index.html: -------------------------------------------------------------------------------- 1 | {% extends "admin_doc/base_docs.html" %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumbs %} 5 | 9 | {% endblock %} 10 | 11 | {% block title %}{% trans 'Documentation' %}{% endblock %} 12 | {% block content_title %}{% trans 'Documentation' %}{% endblock %} 13 | 14 | {% block content %} 15 | 16 |
17 |
18 |
19 |
20 |
{% trans 'Tags' %}
21 |

{% trans 'List of all the template tags and their functions.' %}

22 | 23 |
{% trans 'Filters' %}
24 |

{% trans 'Filters are actions which can be applied to variables in a template to alter the output.' %}

25 | 26 |
{% trans 'Models' %}
27 |

{% trans 'Models are descriptions of all the objects in the system and their associated fields. Each model has a list of fields which can be accessed as template variables' %}.

28 | 29 |
{% trans 'Views' %}
30 |

{% trans 'Each page on the public site is generated by a view. The view defines which template is used to generate the page and which objects are available to that template.' %}

31 | 32 |
{% trans 'Bookmarklets' %}
33 |

{% trans 'Tools for your browser to quickly access admin functionality.' %}

34 |
35 |
36 |
37 |
38 | 39 | {% endblock %} 40 | 41 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/missing_docutils.html: -------------------------------------------------------------------------------- 1 | {% extends "admin_doc/base_docs.html" %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumbs %} 5 | 9 | {% endblock %} 10 | 11 | {% block title %}{% trans 'Please install docutils' %}{% endblock %} 12 | {% block content_title %}{% trans 'Documentation' %}{% endblock %} 13 | 14 | {% block docs_content %} 15 |

{% blocktrans with "http://docutils.sf.net/" as link %}The admin documentation system requires Python's docutils library.{% endblocktrans %}

16 | 17 |

{% blocktrans with "http://docutils.sf.net/" as link %}Please ask your administrators to install docutils.{% endblocktrans %}

18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/model_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "admin_doc/base_docs.html" %} 2 | {% load i18n %} 3 | 4 | {% block extrahead %} 5 | {{ block.super }} 6 | 10 | {% endblock %} 11 | 12 | {% block breadcrumbs %} 13 | 19 | {% endblock %} 20 | 21 | {% block title %}{% blocktrans %}Model: {{ name }}{% endblocktrans %}{% endblock %} 22 | {% block content_title %}{{ name }}{% endblock %} 23 | 24 | {% block docs_content %} 25 |
26 |

{% blocktrans %}Description{% endblocktrans %}

27 |
28 | {{ summary }} 29 | {{ description }} 30 |
31 |
32 | 33 |
34 |

{% trans 'Fields' %}

35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {% for field in fields|dictsort:"name" %} 47 | 48 | 49 | 50 | 51 | 52 | {% endfor %} 53 | 54 |
{% trans 'Field' %}{% trans 'Type' %}{% trans 'Description' %}
{{ field.name }}{{ field.data_type }}{{ field.verbose }}{% if field.help_text %} - {{ field.help_text|safe }}{% endif %}
55 |
56 |
57 | 58 | {% if methods %} 59 |
60 |

{% trans 'Methods with arguments' %}

61 |
62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | {% for method in methods|dictsort:"name" %} 73 | 74 | 75 | 76 | 77 | 78 | {% endfor %} 79 | 80 |
{% trans 'Method' %}{% trans 'Arguments' %}{% trans 'Description' %}
{{ method.name }}{{ method.arguments }}{{ method.verbose }}
81 |
82 |
83 | {% endif %} 84 | 85 |

‹ {% trans 'Back to Model documentation' %}

86 | {% endblock %} 87 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/model_index.html: -------------------------------------------------------------------------------- 1 | {% extends "admin_doc/base_docs.html" %} 2 | {% load i18n %} 3 | 4 | {% block coltype %}colSM{% endblock %} 5 | 6 | {% block breadcrumbs %} 7 | 12 | {% endblock %} 13 | 14 | {% block title %}{% trans 'Models' %}{% endblock %} 15 | {% block content_title %}{% trans 'Models' %}{% endblock %} 16 | 17 | {% block docs_content %} 18 | 19 | {% regroup models by app_config as grouped_models %} 20 | 21 |
22 |
23 | 30 |
31 | 32 |
33 |
34 | {% for group in grouped_models %} 35 |
36 | 37 | 46 | 47 |
48 | {% endfor %} 49 |
50 |
51 |
52 | 53 | {% endblock %} 54 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/template_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumbs %} 5 | 10 | {% endblock %} 11 | 12 | {% block title %}{% blocktrans %}Template: {{ name }}{% endblocktrans %}{% endblock %} 13 | {% block content_title %}{% blocktrans %}Template: {{ name }}{% endblocktrans %}{% endblock %} 14 | 15 | {% block docs_content %} 16 | {# Translators: Search is not a verb here, it qualifies path (a search path) #} 17 |

{% blocktrans %}Search path for template {{ name }}:{% endblocktrans %}

18 |
    19 | {% for template in templates|dictsort:"order" %} 20 |
  1. {{ template.file }}{% if not template.exists %} {% trans '(does not exist)' %}{% endif %}
  2. 21 | {% endfor %} 22 |
23 | 24 |

‹ {% trans 'Back to Documentation' %}

25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/template_filter_index.html: -------------------------------------------------------------------------------- 1 | {% extends "admin_doc/base_docs.html" %} 2 | {% load i18n %} 3 | 4 | {% block coltype %}colSM{% endblock %} 5 | 6 | {% block breadcrumbs %} 7 | 12 | {% endblock %} 13 | 14 | {% block title %}{% trans 'Template filters' %}{% endblock %} 15 | {% block content_title %}{% trans 'Template filters' %}{% endblock %} 16 | 17 | {% block docs_content %} 18 | 19 | {% regroup filters|dictsort:"library" by library as filter_libraries %} 20 | 21 |
22 |
23 | 28 |
29 | 30 |
31 |
32 | {% for library in filter_libraries %} 33 |
34 | {% for view in ns_views.list|dictsort:"url" %} 35 | {% ifchanged %} 36 |

{{ view.url }}

37 |

{% blocktrans with view.full_name as full_name and view.url_name as url_name %}View function: {{ full_name }}. Name: {{ url_name }}.{% endblocktrans %}

38 |

{{ view.title }}

39 |
40 | {% endifchanged %} 41 | {% endfor %} 42 | 43 | {% if library.grouper %}

{% blocktrans with code="{"|add:"% load "|add:library.grouper|add:" %"|add:"}" %}To use these filters, put {{ code }} in your template before using the filter.{% endblocktrans %}


{% endif %} 44 | 45 | {% for filter in library.list|dictsort:"name" %} 46 |

{{ filter.name }}

47 | {{ filter.title }} 48 | {{ filter.body }} 49 | {% if not forloop.last %}
{% endif %} 50 | {% endfor %} 51 |
52 | {% endfor %} 53 |
54 |
55 |
56 | 57 | {% endblock %} 58 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/template_tag_index.html: -------------------------------------------------------------------------------- 1 | {% extends "admin_doc/base_docs.html" %} 2 | {% load i18n %} 3 | 4 | {% block coltype %}colSM{% endblock %} 5 | 6 | {% block breadcrumbs %} 7 | 12 | {% endblock %} 13 | 14 | {% block title %}{% trans 'Template tags' %}{% endblock %} 15 | {% block content_title %}{% trans 'Template tag documentation' %}{% endblock %} 16 | 17 | {% block docs_content %} 18 | 19 | {% regroup tags|dictsort:"library" by library as tag_libraries %} 20 | 21 |
22 |
23 | 28 |
29 | 30 |
31 |
32 | {% for library in tag_libraries %} 33 |
34 | {% if library.grouper %}

{% blocktrans with code="{"|add:"% load "|add:library.grouper|add:" %"|add:"}" %}To use these tags, put {{ code }} in your template before using the tag.{% endblocktrans %}


{% endif %} 35 | {% for tag in library.list|dictsort:"name" %} 36 |

{{ tag.name }}

37 |
{{ tag.title|striptags }}
38 | {{ tag.body }} 39 | {% if not forloop.last %}
{% endif %} 40 | {% endfor %} 41 |
42 | {% endfor %} 43 |
44 |
45 |
46 | 47 | {% endblock %} 48 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/view_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "admin_doc/base_docs.html" %} 2 | {% load i18n jazzmin %} 3 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 4 | 5 | {% block breadcrumbs %} 6 | 12 | {% endblock %} 13 | 14 | {% block title %}{% blocktrans %}View: {{ name }}{% endblocktrans %}{% endblock %} 15 | {% block content_title %}{{ name }}{% endblock %} 16 | 17 | {% block docs_content %} 18 |

{{ summary|striptags }}

19 | 20 | {{ body }} 21 | 22 | {% if meta.Context %} 23 |

{% trans 'Context:' %}

24 |

{{ meta.Context }}

25 | {% endif %} 26 | 27 | {% if meta.Templates %} 28 |

{% trans 'Templates:' %}

29 |

{{ meta.Templates }}

30 | {% endif %} 31 | 32 |
33 |
34 |
35 | {% trans 'Back to View documentation' %} 36 |
37 |
38 |
39 | {% endblock %} 40 | -------------------------------------------------------------------------------- /jazzmin/templates/admin_doc/view_index.html: -------------------------------------------------------------------------------- 1 | {% extends "admin_doc/base_docs.html" %} 2 | {% load i18n %} 3 | 4 | {% block coltype %}colSM{% endblock %} 5 | 6 | {% block breadcrumbs %} 7 | 12 | {% endblock %} 13 | 14 | {% block title %}{% trans 'Views' %}{% endblock %} 15 | {% block content_title %}{% trans 'View documentation' %}{% endblock %} 16 | 17 | {% block docs_content %} 18 | 19 | {% regroup views|dictsort:'namespace' by namespace as views_by_ns %} 20 | 21 |
22 |
23 | 36 |
37 | 38 |
39 |
40 | {% for ns_views in views_by_ns %} 41 |
42 | 43 | {% for view in ns_views.list|dictsort:"url" %} 44 |
45 |
46 |

{{ view.url }}

47 |
48 |
49 |

{% blocktrans with view.full_name as full_name and view.url_name as url_name %}View function: {{ full_name }}. Name: {{ url_name }}.{% endblocktrans %}

50 |

{{ view.title }}

51 |
52 |
53 | 54 | {% endfor %} 55 | 56 |
57 | {% endfor %} 58 |
59 |
60 | {% endblock %} 61 | -------------------------------------------------------------------------------- /jazzmin/templates/jazzmin/includes/carousel.html: -------------------------------------------------------------------------------- 1 | {% load i18n jazzmin %} 2 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 3 | 4 | {% trans "General" as general_tab %} 5 | {% get_sections adminform inline_admin_formsets as forms %} 6 | 7 | 38 | -------------------------------------------------------------------------------- /jazzmin/templates/jazzmin/includes/collapsible.html: -------------------------------------------------------------------------------- 1 | {% load i18n jazzmin %} 2 | {% trans "General" as general_tab %} 3 | {% get_sections adminform inline_admin_formsets as forms %} 4 | 5 |
6 | {% for fieldset in forms %} 7 |
8 |
9 |

10 | {{ fieldset.name|default:general_tab }} 11 |

12 |
13 |
14 |
15 | {% if fieldset.is_inline %} 16 | {% include fieldset.opts.template with inline_admin_formset=fieldset %} 17 | {% else %} 18 | {% include "admin/includes/fieldset.html" with card=True %} 19 | {% endif %} 20 |
21 |
22 |
23 | {% endfor %} 24 |
25 | -------------------------------------------------------------------------------- /jazzmin/templates/jazzmin/includes/horizontal_tabs.html: -------------------------------------------------------------------------------- 1 | {% load i18n jazzmin %} 2 | {% trans "General" as general_tab %} 3 | {% get_sections adminform inline_admin_formsets as forms %} 4 | 5 | {% block tabs %} 6 | 15 | {% endblock tabs %} 16 | 17 |
18 | {% for fieldset in forms %} 19 |
20 | {% if fieldset.is_inline %} 21 | {% include fieldset.opts.template with inline_admin_formset=fieldset %} 22 | {% else %} 23 | {% include "admin/includes/fieldset.html" with card=True %} 24 | {% endif %} 25 |
26 | {% endfor %} 27 |
28 | -------------------------------------------------------------------------------- /jazzmin/templates/jazzmin/includes/related_modal.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 18 | -------------------------------------------------------------------------------- /jazzmin/templates/jazzmin/includes/single.html: -------------------------------------------------------------------------------- 1 | {% load jazzmin %} 2 | {% get_sections adminform inline_admin_formsets as forms %} 3 | 4 | {% for fieldset in forms %} 5 | {% if fieldset.is_inline %} 6 | {% if adminform|has_fieldsets %} 7 |
8 |
9 | {{ fieldset.name }} 10 |
11 |
12 | {% include fieldset.opts.template with inline_admin_formset=fieldset %} 13 |
14 |
15 | {% else %} 16 |
{{ fieldset.name }}
17 | {% include fieldset.opts.template with inline_admin_formset=fieldset %} 18 | {% endif %} 19 | {% else %} 20 | {% include "admin/includes/fieldset.html" with card=adminform|has_fieldsets card_header=adminform|has_fieldsets %} 21 | {% endif %} 22 | {% endfor %} 23 | -------------------------------------------------------------------------------- /jazzmin/templates/jazzmin/includes/vertical_tabs.html: -------------------------------------------------------------------------------- 1 | {% load i18n jazzmin %} 2 | {% trans "General" as general_tab %} 3 | {% get_sections adminform inline_admin_formsets as forms %} 4 | 5 |
6 |
7 | 14 |
15 |
16 |
17 | {% for fieldset in forms %} 18 |
19 | {% if fieldset.is_inline %} 20 | {% include fieldset.opts.template with inline_admin_formset=fieldset %} 21 | {% else %} 22 | {% include "admin/includes/fieldset.html" with card=True %} 23 | {% endif %} 24 |
25 | {% endfor %} 26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /jazzmin/templates/jazzmin/widgets/select.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /jazzmin/templates/registration/base.html: -------------------------------------------------------------------------------- 1 | {% load i18n static jazzmin admin_urls %} 2 | {% get_current_language as LANGUAGE_CODE %} 3 | {% get_current_language_bidi as LANGUAGE_BIDI %} 4 | {% get_jazzmin_settings request as jazzmin_settings %} 5 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% block title %}{{ title }} | {{ jazzmin_settings.site_title }}{% endblock %} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% if jazzmin_ui.theme.name != 'default' %} 24 | 25 | {% endif %} 26 | 27 | {% if jazzmin_ui.dark_mode_theme %} 28 | 29 | {% endif %} 30 | 31 | 32 | 33 | 34 | {% if jazzmin_settings.custom_css %} 35 | 36 | 37 | {% endif %} 38 | 39 | 40 | 41 | 42 | 43 | {% if jazzmin_settings.use_google_fonts_cdn %} 44 | 45 | 46 | {% endif %} 47 | 48 | {% block extrastyle %} {% endblock %} 49 | {% block extrahead %} {% endblock %} 50 | 51 | 52 | 53 |
54 | 64 | 65 |
66 |
67 | {% block content %} {% endblock %} 68 |
69 |
70 |
71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | {% if jazzmin_settings.custom_js %} 80 | 81 | {% endif %} 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /jazzmin/templates/registration/logged_out.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block content %} 6 |

{{ jazzmin_settings.welcome_sign }}

7 |

8 | {% trans "Thanks for spending some quality time with the web site today." %} 9 |

10 | 11 | {% trans 'Log in again' %} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /jazzmin/templates/registration/password_change_done.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n %} 3 | {% block userlinks %} 4 | {% url 'django-admindocs-docroot' as docsroot %} 5 | {% if docsroot %}{% trans 'Documentation' %} / {% endif %} 6 | {% trans 'Change password' %} / 7 | {% trans 'Log out' %} 8 | {% endblock %} 9 | {% block breadcrumbs %} 10 | 14 | {% endblock %} 15 | 16 | {% block title %}{{ title }}{% endblock %} 17 | {% block content_title %} {{ title }} {% endblock %} 18 | {% block content %} 19 |
20 |
21 |

{% trans 'Your password was changed.' %}

22 |
23 |
24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /jazzmin/templates/registration/password_reset_complete.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block content %} 6 |

{% trans "Your password has been set. You may go ahead and log in now." %}

7 |
8 | 13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /jazzmin/templates/registration/password_reset_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block content %} 6 | {% if validlink %} 7 |

8 | {% trans "Please enter your new password twice so we can verify you typed it in correctly." %} 9 |

10 |
{% csrf_token %} 11 | {% if form.errors %} 12 | {% if form.new_password1.errors %} 13 |
14 |

{{ form.new_password1.label }}: {{ form.new_password1.errors|join:', ' }}

15 |
16 | {% endif %} 17 | {% if form.new_password2.errors %} 18 |
19 |

{{ form.new_password2.label }}: {{ form.new_password2.errors|join:', ' }}

20 |
21 | {% endif %} 22 | {% if form.non_field_errors %} 23 |
24 | {% for error in form.non_field_errors %} 25 |

{{ error }}

26 | {% endfor %} 27 |
28 | {% endif %} 29 | {% endif %} 30 | 31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 |
39 |
40 | 41 |
42 |
43 | 44 |
45 |
46 |
47 |
48 |
49 | 52 |
53 |
54 |
55 | {% else %} 56 |

57 | {% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %} 58 |

59 | {% endif %} 60 | {% endblock %} 61 | -------------------------------------------------------------------------------- /jazzmin/templates/registration/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block content %} 6 |

7 | {% blocktrans trimmed %} 8 | We’ve emailed you instructions for setting your password, 9 | if an account exists with the email you entered. 10 | You should receive them shortly. 11 | {% endblocktrans %} 12 |

13 |

14 | {% blocktrans trimmed %} 15 | If you don’t receive an email, please make sure 16 | you’ve entered the address you registered with, 17 | and check your spam folder. 18 | {% endblocktrans %} 19 |

20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /jazzmin/templates/registration/password_reset_form.html: -------------------------------------------------------------------------------- 1 | {% extends "registration/base.html" %} 2 | 3 | {% load i18n jazzmin %} 4 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 5 | 6 | {% block content %} 7 |

8 | {% blocktrans trimmed %} 9 | Forgotten your password? 10 | Enter your email address below, and we’ll 11 | email instructions for setting a new one. 12 | {% endblocktrans %} 13 |

14 |
15 | {% csrf_token %} 16 | {% if form.errors %} 17 | {% if form.email.errors %} 18 |
19 |

{{ form.email.label }}: {{ form.email.errors|join:', ' }}

20 |
21 | {% endif %} 22 | {% if form.non_field_errors %} 23 |
24 | {% for error in form.non_field_errors %} 25 |

{{ error }}

26 | {% endfor %} 27 |
28 | {% endif %} 29 | {% endif %} 30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 |
38 |
39 |
40 | 43 |
44 |
45 |
46 | {% endblock %} 47 | -------------------------------------------------------------------------------- /jazzmin/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/jazzmin/templatetags/__init__.py -------------------------------------------------------------------------------- /jazzmin/widgets.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.forms.widgets import Select, SelectMultiple 3 | 4 | 5 | class JazzminSelect(Select): 6 | template_name = "jazzmin/widgets/select.html" 7 | 8 | @property 9 | def media(self): 10 | return forms.Media( 11 | css={"all": ("vendor/select2/css/select2.min.css",)}, 12 | js=("vendor/select2/js/select2.min.js",), 13 | ) 14 | 15 | 16 | class JazzminSelectMultiple(SelectMultiple): 17 | template_name = "jazzmin/widgets/select.html" 18 | 19 | def build_attrs(self, base_attrs, extra_attrs=None): 20 | extra_attrs["multiple"] = "multiple" 21 | return {**base_attrs, **(extra_attrs or {})} 22 | 23 | @property 24 | def media(self): 25 | return forms.Media( 26 | css={"all": ("vendor/select2/css/select2.min.css",)}, 27 | js=("vendor/select2/js/select2.min.js",), 28 | ) 29 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Jazzmin 2 | nav: 3 | - Home: index.md 4 | - Installation: installation.md 5 | - Configuration: configuration.md 6 | - UI Tweaks: ui_customisation.md 7 | - Bugs/Features: bugs_and_features.md 8 | - Development: development.md 9 | theme: readthedocs 10 | 11 | markdown_extensions: 12 | - toc: 13 | permalink: true 14 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/__init__.py -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | import pytest 4 | from django.urls import reverse 5 | 6 | from .test_app.library.factories import BookFactory 7 | 8 | 9 | @pytest.fixture 10 | def change_form_context(admin_client): 11 | book = BookFactory() 12 | url = reverse("admin:books_book_change", args=(book.pk,)) 13 | response = admin_client.get(url) 14 | yield response.context 15 | 16 | 17 | @pytest.fixture(scope="function") 18 | def custom_jazzmin_settings(settings): 19 | original_settings = copy.deepcopy(settings.JAZZMIN_SETTINGS) 20 | settings.JAZZMIN_SETTINGS = original_settings 21 | yield original_settings 22 | -------------------------------------------------------------------------------- /tests/test_app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/__init__.py -------------------------------------------------------------------------------- /tests/test_app/library/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/__init__.py -------------------------------------------------------------------------------- /tests/test_app/library/books/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/books/__init__.py -------------------------------------------------------------------------------- /tests/test_app/library/books/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.contrib.admin.models import LogEntry 3 | from django.contrib.auth.admin import UserAdmin 4 | from django.contrib.auth.models import User 5 | from django.utils.html import format_html 6 | from django.utils.timesince import timesince 7 | 8 | from jazzmin.utils import attr 9 | 10 | from ..loans.admin import BookLoanInline 11 | from .models import Author, Book, Genre 12 | 13 | admin.site.unregister(User) 14 | 15 | 16 | class BooksInline(admin.TabularInline): 17 | model = Book 18 | 19 | 20 | @admin.register(Book) 21 | class BookAdmin(admin.ModelAdmin): 22 | fieldsets = ( 23 | ("general", {"fields": ("title", "author", "library"), "description": "General book fields"}), 24 | ("other", {"fields": ("genre", "summary", "isbn", "published_on", "pages")}), 25 | ) 26 | raw_id_fields = ("author",) 27 | list_display = ("__str__", "title", "author", "pages") 28 | readonly_fields = ("__str__",) 29 | list_per_page = 20 30 | list_max_show_all = 100 31 | list_editable = ("title",) 32 | search_fields = ("title", "author__last_name") 33 | autocomplete_fields = ("genre",) 34 | date_hierarchy = "published_on" 35 | save_as = True 36 | save_on_top = True 37 | inlines = (BookLoanInline,) 38 | 39 | actions_on_bottom = True 40 | 41 | # Order the sections within the change form 42 | jazzmin_section_order = ("book loans", "general", "other") 43 | 44 | 45 | @admin.register(Author) 46 | class AuthorAdmin(admin.ModelAdmin): 47 | list_display = ("last_name", "first_name", "date_of_birth", "date_of_death") 48 | fields = ("first_name", "last_name", ("date_of_birth", "date_of_death")) 49 | inlines = (BooksInline,) 50 | 51 | 52 | @admin.register(LogEntry) 53 | class LogEntryAdmin(admin.ModelAdmin): 54 | list_display = ("user", "object", "action_flag", "change_message", "modified") 55 | readonly_fields = ["object", "modified"] 56 | search_fields = ("user__email",) 57 | date_hierarchy = "action_time" 58 | list_filter = ("action_flag", "content_type__model") 59 | list_per_page = 20 60 | 61 | def object(self, obj): 62 | url = obj.get_admin_url() 63 | return format_html( 64 | '{obj} [{model}]'.format(url=url, obj=obj.object_repr, model=obj.content_type.model) 65 | ) 66 | 67 | @attr(admin_order_field="action_time") 68 | def modified(self, obj): 69 | if not obj.action_time: 70 | return "Never" 71 | return "{} ago".format(timesince(obj.action_time)) 72 | 73 | 74 | @admin.register(User) 75 | class CustomUserAdmin(UserAdmin): 76 | def get_queryset(self, request): 77 | """ 78 | Remove our test user from the admin, so it cant be messed with 79 | """ 80 | return super(CustomUserAdmin, self).get_queryset(request).exclude(username="test@test.com") 81 | 82 | 83 | @admin.register(Genre) 84 | class GenreAdmin(admin.ModelAdmin): 85 | search_fields = ("name",) 86 | -------------------------------------------------------------------------------- /tests/test_app/library/books/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class BooksConfig(AppConfig): 5 | name = "tests.test_app.library.books" 6 | 7 | def ready(self): 8 | from . import receivers # NOQA 9 | -------------------------------------------------------------------------------- /tests/test_app/library/books/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/books/management/__init__.py -------------------------------------------------------------------------------- /tests/test_app/library/books/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/books/management/commands/__init__.py -------------------------------------------------------------------------------- /tests/test_app/library/books/management/commands/reset.py: -------------------------------------------------------------------------------- 1 | from random import choice 2 | 3 | from django.contrib.auth.models import Group, User 4 | from django.core.management import BaseCommand 5 | 6 | from ....factories import ( 7 | AuthorFactory, 8 | BookFactory, 9 | BookLoanFactory, 10 | GroupFactory, 11 | LibraryFactory, 12 | UserFactory, 13 | ) 14 | from ....loans.models import BookLoan, Library 15 | from ...models import Author, Book, Genre 16 | 17 | 18 | class Command(BaseCommand): 19 | """ 20 | A management script for resetting all data 21 | """ 22 | 23 | def handle(self, *args, **options): 24 | for Model in [Group, User, Library, Author, Book, BookLoan, Genre]: 25 | Model.objects.all().delete() 26 | 27 | library = LibraryFactory() 28 | UserFactory( 29 | username="test@test.com", 30 | email="test@test.com", 31 | password="test", 32 | is_superuser=True, 33 | ) 34 | 35 | users = UserFactory.create_batch(2, is_staff=False) 36 | 37 | GroupFactory.create_batch(5) 38 | 39 | for author in AuthorFactory.create_batch(10): 40 | for book in BookFactory.create_batch(5, author=author, library=library): 41 | BookLoanFactory(book=book, borrower=choice(users)) 42 | 43 | self.stdout.write("All Data reset") 44 | -------------------------------------------------------------------------------- /tests/test_app/library/books/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.15 on 2020-10-14 12:37 2 | from typing import List 3 | 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies: List[str] = [] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name="Author", 17 | fields=[ 18 | ( 19 | "id", 20 | models.AutoField( 21 | auto_created=True, 22 | primary_key=True, 23 | serialize=False, 24 | verbose_name="ID", 25 | ), 26 | ), 27 | ("first_name", models.CharField(max_length=100)), 28 | ("last_name", models.CharField(max_length=100)), 29 | ("date_of_birth", models.DateField(blank=True, null=True)), 30 | ( 31 | "date_of_death", 32 | models.DateField(blank=True, null=True, verbose_name="Died"), 33 | ), 34 | ], 35 | options={ 36 | "ordering": ("last_name", "first_name"), 37 | }, 38 | ), 39 | migrations.CreateModel( 40 | name="Genre", 41 | fields=[ 42 | ( 43 | "id", 44 | models.AutoField( 45 | auto_created=True, 46 | primary_key=True, 47 | serialize=False, 48 | verbose_name="ID", 49 | ), 50 | ), 51 | ( 52 | "name", 53 | models.CharField( 54 | help_text="Enter a book genre (e.g. Science Fiction)", 55 | max_length=200, 56 | ), 57 | ), 58 | ], 59 | ), 60 | migrations.CreateModel( 61 | name="Book", 62 | fields=[ 63 | ( 64 | "id", 65 | models.AutoField( 66 | auto_created=True, 67 | primary_key=True, 68 | serialize=False, 69 | verbose_name="ID", 70 | ), 71 | ), 72 | ("title", models.CharField(max_length=200)), 73 | ( 74 | "summary", 75 | models.TextField( 76 | help_text="Enter a brief description of the book", 77 | max_length=1000, 78 | ), 79 | ), 80 | ( 81 | "isbn", 82 | models.CharField( 83 | help_text='13 Character ISBN number', 84 | max_length=13, 85 | verbose_name="ISBN", 86 | ), 87 | ), 88 | ("published_on", models.DateField()), 89 | ( 90 | "author", 91 | models.ForeignKey( 92 | null=True, 93 | on_delete=django.db.models.deletion.SET_NULL, 94 | to="books.Author", 95 | ), 96 | ), 97 | ( 98 | "genre", 99 | models.ManyToManyField(help_text="Select a genre for this book", to="books.Genre"), 100 | ), 101 | ], 102 | ), 103 | ] 104 | -------------------------------------------------------------------------------- /tests/test_app/library/books/migrations/0002_book_library.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.15 on 2020-10-14 12:37 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ("loans", "0001_initial"), 13 | ("books", "0001_initial"), 14 | ] 15 | 16 | operations = [ 17 | migrations.AddField( 18 | model_name="book", 19 | name="library", 20 | field=models.ForeignKey( 21 | on_delete=django.db.models.deletion.CASCADE, 22 | related_name="books", 23 | to="loans.Library", 24 | ), 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /tests/test_app/library/books/migrations/0003_auto_20201015_1222.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.15 on 2020-10-15 11:22 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ("books", "0002_book_library"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name="book", 15 | name="isbn", 16 | field=models.CharField( 17 | help_text=( 18 | '13 Character ISBN number', 19 | ), 20 | max_length=13, 21 | verbose_name="ISBN", 22 | ), 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /tests/test_app/library/books/migrations/0004_book_pages.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.5 on 2021-01-18 15:37 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ("books", "0003_auto_20201015_1222"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name="book", 15 | name="pages", 16 | field=models.IntegerField(null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /tests/test_app/library/books/migrations/0005_book_last_print.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.16 on 2021-02-26 21:49 2 | 3 | import datetime 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ("books", "0004_book_pages"), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name="book", 16 | name="last_print", 17 | field=models.DateField(default=datetime.date(2000, 1, 1)), 18 | preserve_default=False, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /tests/test_app/library/books/migrations/0006_auto_20220327_0814.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.12 on 2022-03-27 07:14 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ("books", "0005_book_last_print"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name="author", 15 | name="id", 16 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), 17 | ), 18 | migrations.AlterField( 19 | model_name="book", 20 | name="id", 21 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), 22 | ), 23 | migrations.AlterField( 24 | model_name="genre", 25 | name="id", 26 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /tests/test_app/library/books/migrations/0007_auto_20220715_1109.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.13 on 2022-07-15 10:09 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ("books", "0006_auto_20220327_0814"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name="book", 15 | name="last_print", 16 | field=models.DateField(auto_now_add=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /tests/test_app/library/books/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/books/migrations/__init__.py -------------------------------------------------------------------------------- /tests/test_app/library/books/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.urls import reverse 3 | 4 | 5 | class Genre(models.Model): 6 | name = models.CharField(max_length=200, help_text="Enter a book genre (e.g. Science Fiction)") 7 | 8 | def __str__(self): 9 | return self.name 10 | 11 | 12 | class Book(models.Model): 13 | title = models.CharField(max_length=200) 14 | library = models.ForeignKey("loans.Library", related_name="books", on_delete=models.CASCADE) 15 | author = models.ForeignKey("Author", on_delete=models.SET_NULL, null=True) 16 | summary = models.TextField(max_length=1000, help_text="Enter a brief description of the book") 17 | isbn = models.CharField( 18 | "ISBN", 19 | max_length=13, 20 | help_text=( 21 | "13 Character " '' "ISBN number", 22 | ), 23 | ) 24 | genre = models.ManyToManyField(Genre, help_text="Select a genre for this book") 25 | published_on = models.DateField() 26 | last_print = models.DateField(auto_now_add=True) 27 | pages = models.IntegerField(null=True) 28 | 29 | def get_absolute_url(self): 30 | return reverse("admin:books_book_change", args=(self.id,)) 31 | 32 | def __str__(self): 33 | return self.title 34 | 35 | 36 | class Author(models.Model): 37 | first_name = models.CharField(max_length=100) 38 | last_name = models.CharField(max_length=100) 39 | date_of_birth = models.DateField(null=True, blank=True) 40 | date_of_death = models.DateField("Died", null=True, blank=True) 41 | 42 | class Meta: 43 | ordering = ("last_name", "first_name") 44 | 45 | def get_absolute_url(self): 46 | return reverse("admin:books_author_change", args=(self.id,)) 47 | 48 | def __str__(self): 49 | return "{}, {}".format(self.first_name, self.last_name) 50 | -------------------------------------------------------------------------------- /tests/test_app/library/books/receivers.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.db.models.signals import pre_save 3 | from django.dispatch import receiver 4 | 5 | 6 | @receiver(pre_save, sender=User) 7 | def add_user_levels_actions(sender, instance, **kwargs): 8 | """ 9 | Dont allow our test user to change their password 10 | """ 11 | if instance.username == "test@test.com": 12 | instance.set_password("test") 13 | -------------------------------------------------------------------------------- /tests/test_app/library/books/static/books/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/books/static/books/img/icon.png -------------------------------------------------------------------------------- /tests/test_app/library/books/static/books/img/logo-login-dark-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/books/static/books/img/logo-login-dark-mode.png -------------------------------------------------------------------------------- /tests/test_app/library/books/static/books/img/logo-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/books/static/books/img/logo-login.png -------------------------------------------------------------------------------- /tests/test_app/library/books/static/books/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/books/static/books/img/logo.png -------------------------------------------------------------------------------- /tests/test_app/library/books/templates/admin/loans/bookloan/submit_line.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/submit_line.html" %} 2 | {% load jazzmin %} 3 | {% get_jazzmin_ui_tweaks as jazzmin_ui %} 4 | 5 | {% block extra-actions %} 6 | 7 | {# Simple link #} 8 |
9 | Go Django 10 |
11 | 12 | {# Process with form submission #} 13 |
14 | 15 |
16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /tests/test_app/library/loans/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/loans/__init__.py -------------------------------------------------------------------------------- /tests/test_app/library/loans/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path 3 | 4 | from .models import BookLoan, Library 5 | from .views import CustomView 6 | 7 | 8 | class BookLoanInline(admin.StackedInline): 9 | model = BookLoan 10 | extra = 1 11 | readonly_fields = ("id", "duration") 12 | fields = ( 13 | "book", 14 | "imprint", 15 | "status", 16 | "due_back", 17 | "borrower", 18 | "loan_start", 19 | "duration", 20 | ) 21 | 22 | 23 | @admin.register(BookLoan) 24 | class BookLoanAdmin(admin.ModelAdmin): 25 | list_display = ("book", "status", "borrower", "due_back", "id") 26 | list_filter = ("status", "due_back") 27 | autocomplete_fields = ("borrower",) 28 | search_fields = ("book__title",) 29 | readonly_fields = ("id",) 30 | fieldsets = ( 31 | (None, {"fields": ("book", "imprint", "id")}), 32 | ("Availability", {"fields": ("status", "due_back", "duration", "borrower")}), 33 | ) 34 | 35 | def get_urls(self): 36 | """ 37 | Add in a custom view to demonstrate = 38 | """ 39 | urls = super().get_urls() 40 | return urls + [path("custom_view", CustomView.as_view(), name="custom_view")] 41 | 42 | def response_change(self, request, obj): 43 | ret = super().response_change(request, obj) 44 | 45 | if "reserve" in request.POST: 46 | obj.status = "r" 47 | obj.save() 48 | return ret 49 | 50 | 51 | @admin.register(Library) 52 | class LibraryAdmin(admin.ModelAdmin): 53 | list_display = ("name", "address", "librarian") 54 | -------------------------------------------------------------------------------- /tests/test_app/library/loans/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class LoansConfig(AppConfig): 5 | name = "tests.test_app.library.loans" 6 | -------------------------------------------------------------------------------- /tests/test_app/library/loans/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.15 on 2020-10-14 12:37 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | import uuid 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ("books", "0001_initial"), 15 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name="Library", 21 | fields=[ 22 | ( 23 | "id", 24 | models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), 25 | ), 26 | ("address", models.CharField(max_length=255)), 27 | ( 28 | "librarian", 29 | models.OneToOneField( 30 | on_delete=django.db.models.deletion.CASCADE, related_name="library", to=settings.AUTH_USER_MODEL 31 | ), 32 | ), 33 | ], 34 | ), 35 | migrations.CreateModel( 36 | name="BookLoan", 37 | fields=[ 38 | ( 39 | "id", 40 | models.UUIDField( 41 | default=uuid.uuid4, 42 | help_text="Unique ID for this particular book across whole library", 43 | primary_key=True, 44 | serialize=False, 45 | ), 46 | ), 47 | ("imprint", models.CharField(max_length=200)), 48 | ("due_back", models.DateField(blank=True, null=True)), 49 | ("loan_start", models.DateTimeField()), 50 | ("duration", models.DurationField(blank=True)), 51 | ( 52 | "status", 53 | models.CharField( 54 | blank=True, 55 | choices=[ 56 | ("m", "Maintenance"), 57 | ("o", "On loan"), 58 | ("a", "Available"), 59 | ("r", "Reserved"), 60 | ], 61 | default="m", 62 | help_text="Book availability", 63 | max_length=1, 64 | ), 65 | ), 66 | ( 67 | "book", 68 | models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to="books.Book"), 69 | ), 70 | ( 71 | "borrower", 72 | models.ForeignKey( 73 | blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL 74 | ), 75 | ), 76 | ], 77 | options={ 78 | "ordering": ("due_back",), 79 | }, 80 | ), 81 | ] 82 | -------------------------------------------------------------------------------- /tests/test_app/library/loans/migrations/0002_auto_20201015_1222.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.15 on 2020-10-15 11:22 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ("loans", "0001_initial"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterModelOptions( 14 | name="library", 15 | options={"verbose_name_plural": "Libraries"}, 16 | ), 17 | migrations.AddField( 18 | model_name="library", 19 | name="name", 20 | field=models.CharField(default=1, max_length=255), 21 | preserve_default=False, 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /tests/test_app/library/loans/migrations/0003_alter_library_id.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.12 on 2022-03-27 07:14 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ("loans", "0002_auto_20201015_1222"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name="library", 15 | name="id", 16 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID"), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /tests/test_app/library/loans/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farridav/django-jazzmin/d269874c96fe5ff6d231c3017cdd4650bc2f3105/tests/test_app/library/loans/migrations/__init__.py -------------------------------------------------------------------------------- /tests/test_app/library/loans/models.py: -------------------------------------------------------------------------------- 1 | from uuid import uuid4 2 | 3 | from django.conf import settings 4 | from django.db import models 5 | from django.utils import timezone 6 | 7 | 8 | class Library(models.Model): 9 | name = models.CharField(max_length=255) 10 | address = models.CharField(max_length=255) 11 | librarian = models.OneToOneField(settings.AUTH_USER_MODEL, related_name="library", on_delete=models.CASCADE) 12 | 13 | class Meta: 14 | verbose_name_plural = "Libraries" 15 | 16 | def __str__(self): 17 | return self.address 18 | 19 | 20 | class BookLoan(models.Model): 21 | id = models.UUIDField( 22 | primary_key=True, 23 | default=uuid4, 24 | help_text="Unique ID for this particular book across whole library", 25 | ) 26 | book = models.ForeignKey("books.Book", on_delete=models.SET_NULL, null=True) 27 | imprint = models.CharField(max_length=200) 28 | loan_start = models.DateTimeField() 29 | due_back = models.DateField(null=True, blank=True) 30 | 31 | duration = models.DurationField(blank=True) 32 | 33 | LOAN_STATUS = ( 34 | ("m", "Maintenance"), 35 | ("o", "On loan"), 36 | ("a", "Available"), 37 | ("r", "Reserved"), 38 | ) 39 | borrower = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True) 40 | status = models.CharField( 41 | max_length=1, 42 | choices=LOAN_STATUS, 43 | blank=True, 44 | default="m", 45 | help_text="Book availability", 46 | ) 47 | 48 | class Meta: 49 | ordering = ("due_back",) 50 | 51 | def __str__(self): 52 | return "{}, ({})".format(self.id, self.book.title) 53 | 54 | def save(self, **kwargs): 55 | self.duration = self.loan_start - timezone.now() 56 | super().save(**kwargs) 57 | -------------------------------------------------------------------------------- /tests/test_app/library/loans/templates/loans/custom.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% block content %} 3 | 4 |
5 |
6 |
7 |
8 | Some title 9 |
10 |
11 |
12 | Some content 13 |
14 |
15 |
16 | 17 |
18 |
19 |
20 |
21 | Some title 22 |
23 |
24 |
25 | Some content 26 |
27 |
28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /tests/test_app/library/loans/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.admin.sites import site 2 | from django.views.generic import TemplateView 3 | 4 | 5 | class CustomView(TemplateView): 6 | template_name = "loans/custom.html" 7 | 8 | def get_context_data(self, **kwargs): 9 | ctx = super().get_context_data(**kwargs) 10 | ctx.update(site.each_context(self.request)) 11 | return ctx 12 | -------------------------------------------------------------------------------- /tests/test_app/library/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls.i18n import i18n_patterns 3 | from django.contrib import admin, messages 4 | from django.contrib.auth import views as auth_views 5 | from django.http import HttpResponseRedirect 6 | from django.urls import include, path, re_path, reverse 7 | from django.views.generic import RedirectView 8 | from django.views.static import serve 9 | 10 | 11 | def make_messages(request): 12 | messages.add_message(request, messages.INFO, "Info message") 13 | messages.add_message(request, messages.ERROR, "Error message") 14 | messages.add_message(request, messages.WARNING, "Warning message") 15 | messages.add_message(request, messages.SUCCESS, "Success message") 16 | 17 | return HttpResponseRedirect(reverse("admin:index")) 18 | 19 | 20 | urlpatterns = [ 21 | path("", RedirectView.as_view(pattern_name="admin:index", permanent=False)), 22 | path("admin/doc/", include("django.contrib.admindocs.urls")), 23 | path("make_messages/", make_messages, name="make_messages"), 24 | path("i18n/", include("django.conf.urls.i18n")), 25 | ] 26 | 27 | urlpatterns += i18n_patterns( 28 | path("admin/password_reset/", auth_views.PasswordResetView.as_view(), name="admin_password_reset"), 29 | path("admin/password_reset/done/", auth_views.PasswordResetDoneView.as_view(), name="password_reset_done"), 30 | path("reset///", auth_views.PasswordResetConfirmView.as_view(), name="password_reset_confirm"), 31 | path("reset/done/", auth_views.PasswordResetCompleteView.as_view(), name="password_reset_complete"), 32 | path("admin/", admin.site.urls), 33 | ) 34 | 35 | if settings.DEBUG: 36 | urlpatterns.append(re_path(r"^static/(?P.*)$", serve, kwargs={"document_root": settings.STATIC_ROOT})) 37 | 38 | if "debug_toolbar" in settings.INSTALLED_APPS: 39 | try: 40 | import debug_toolbar 41 | 42 | urlpatterns.append(path("__debug__/", include(debug_toolbar.urls))) 43 | except ImportError: 44 | pass 45 | -------------------------------------------------------------------------------- /tests/test_app/library/wsgi.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from django.core.wsgi import get_wsgi_application 4 | 5 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "library.settings") 6 | 7 | application = get_wsgi_application() 8 | -------------------------------------------------------------------------------- /tests/test_app/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "library.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /tests/test_app/requirements.txt: -------------------------------------------------------------------------------- 1 | Django 2 | whitenoise 3 | gunicorn 4 | psycopg2-binary 5 | dj-database-url 6 | factory-boy 7 | docutils 8 | importlib-metadata==4.13.0 9 | django-debug-toolbar 10 | django_extensions 11 | django-jazzmin -------------------------------------------------------------------------------- /tests/test_init.py: -------------------------------------------------------------------------------- 1 | import jazzmin 2 | 3 | 4 | def test_version(): 5 | """ 6 | Tests getting the version of the installed package in all versions of Python we support. 7 | """ 8 | assert jazzmin.version >= "0.0.0" 9 | -------------------------------------------------------------------------------- /tests/test_permissions.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from django.urls import reverse 3 | 4 | from .test_app.library.factories import BookFactory, UserFactory 5 | from .utils import parse_sidemenu 6 | 7 | 8 | @pytest.mark.django_db 9 | def test_no_delete_permission(client): 10 | """ 11 | When our user has no delete permission, they dont see things they are not supposed to 12 | """ 13 | user = UserFactory(permissions=["books.view_book"]) 14 | book = BookFactory() 15 | 16 | url = reverse("admin:books_book_change", args=(book.pk,)) 17 | delete_url = reverse("admin:books_book_delete", args=(book.pk,)) 18 | client.force_login(user) 19 | 20 | response = client.get(url) 21 | assert delete_url not in response.content.decode() 22 | 23 | 24 | @pytest.mark.django_db 25 | def test_no_add_permission(client): 26 | """ 27 | When our user has no add permission, they dont see things they are not supposed to 28 | """ 29 | user = UserFactory(permissions=["books.view_book"]) 30 | url = reverse("admin:books_book_changelist") 31 | add_url = reverse("admin:books_book_add") 32 | 33 | client.force_login(user) 34 | response = client.get(url) 35 | 36 | assert add_url not in response.content.decode() 37 | 38 | 39 | @pytest.mark.django_db 40 | def test_delete_but_no_view_permission(client): 41 | """ 42 | When our user has delete but no view/change permission, menu items render out, but with no links 43 | 44 | As in Plain old Django Admin 45 | """ 46 | user = UserFactory(permissions=["books.delete_book"]) 47 | 48 | url = reverse("admin:index") 49 | client.force_login(user) 50 | 51 | response = client.get(url) 52 | assert parse_sidemenu(response) == {"Global": ["/en/admin/"], "Books": [None]} 53 | 54 | 55 | @pytest.mark.django_db 56 | def test_no_permission(client): 57 | """ 58 | When our user has no permissions at all, they see no menu or dashboard 59 | 60 | As in Plain old Django Admin 61 | """ 62 | user = UserFactory(permissions=[]) 63 | 64 | url = reverse("admin:index") 65 | client.force_login(user) 66 | 67 | response = client.get(url) 68 | assert parse_sidemenu(response) == {"Global": ["/en/admin/"]} 69 | -------------------------------------------------------------------------------- /tests/test_settings.py: -------------------------------------------------------------------------------- 1 | from jazzmin.settings import get_search_model_string 2 | 3 | 4 | def test_get_search_model_string(): 5 | # model name is always lower case 6 | assert get_search_model_string("books.Book") == "books.book" 7 | assert get_search_model_string("books.book") == "books.book" 8 | # the app name gets never touched 9 | assert get_search_model_string("Books.Book") == "Books.book" 10 | assert get_search_model_string("BookShelf.book") == "BookShelf.book" 11 | -------------------------------------------------------------------------------- /tests/test_templatetags.py: -------------------------------------------------------------------------------- 1 | import json 2 | from unittest.mock import MagicMock, NonCallableMock 3 | 4 | import pytest 5 | from django.contrib.admin.models import CHANGE, LogEntry 6 | 7 | from jazzmin.templatetags import jazzmin 8 | 9 | 10 | @pytest.mark.django_db 11 | def test_app_is_installed(settings): 12 | """ 13 | Returns True if an app is under INSTALLED_APPS, False otherwise 14 | """ 15 | app = "test_app" 16 | 17 | assert jazzmin.app_is_installed(app) is False 18 | 19 | settings.INSTALLED_APPS.append(app) 20 | 21 | assert jazzmin.app_is_installed(app) is True 22 | 23 | 24 | @pytest.mark.django_db 25 | def test_action_message_to_list(admin_user): 26 | """ 27 | We can generate a list of messages from a log entry object 28 | """ 29 | message = [ 30 | {"changed": {"fields": ["Owner", "Text", "Pub date", "Active"]}}, 31 | {"added": {"name": "choice", "object": "More random choices"}}, 32 | {"deleted": {"name": "choice", "object": "Person serious choose tea"}}, 33 | ] 34 | log_entry = LogEntry.objects.create(user=admin_user, action_flag=CHANGE, change_message=json.dumps(message)) 35 | assert jazzmin.action_message_to_list(log_entry) == [ 36 | {"msg": "Changed Owner, Text, Pub date and Active.", "icon": "edit", "colour": "blue"}, 37 | {"msg": "Added choice “More random choices”.", "icon": "plus-circle", "colour": "success"}, 38 | {"msg": "Deleted “Person serious choose tea”.", "icon": "trash", "colour": "danger"}, 39 | ] 40 | 41 | 42 | def test_style_bold_first_word(): 43 | """ 44 | Adds HTML element wrapping first word given a sentence 45 | """ 46 | message = "The bomb has been planted" 47 | 48 | assert jazzmin.style_bold_first_word(message) == "The bomb has been planted" 49 | 50 | 51 | @pytest.mark.django_db 52 | @pytest.mark.parametrize( 53 | "case,test_input,field,expected,log", 54 | [ 55 | (1, MagicMock(avatar="image.jpg"), "avatar", "image.jpg", None), 56 | (2, MagicMock(avatar="image.jpg"), lambda u: u.avatar, "image.jpg", None), 57 | (3, MagicMock(avatar=MagicMock(url="image.jpg")), "avatar", "image.jpg", None), 58 | # Properly set file field but empty (no image uploaded) 59 | ( 60 | 4, 61 | MagicMock(avatar=MagicMock(__bool__=lambda x: False)), 62 | "avatar", 63 | "/static/vendor/adminlte/img/user2-160x160.jpg", 64 | None, 65 | ), 66 | # No avatar field set 67 | ( 68 | 5, 69 | MagicMock( 70 | avatar="image.jpg", 71 | ), 72 | None, 73 | "/static/vendor/adminlte/img/user2-160x160.jpg", 74 | None, 75 | ), 76 | # No proper avatar field set 77 | ( 78 | 6, 79 | MagicMock(avatar=NonCallableMock(spec_set=["__bool__"], __bool__=lambda x: True)), 80 | "avatar", 81 | "/static/vendor/adminlte/img/user2-160x160.jpg", 82 | "Avatar field must be", 83 | ), 84 | ], 85 | ) 86 | def test_get_user_avatar(case, test_input, field, expected, log, custom_jazzmin_settings, caplog): 87 | """ 88 | We can specify the name of a charfield or imagefield on our user model, or a callable that receives our user 89 | """ 90 | custom_jazzmin_settings["user_avatar"] = field 91 | assert jazzmin.get_user_avatar(test_input) == expected 92 | if log: 93 | assert log in caplog.text 94 | else: 95 | assert not caplog.text 96 | -------------------------------------------------------------------------------- /tests/utils.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | from bs4 import BeautifulSoup, Tag 4 | from faker import Faker 5 | 6 | fake = Faker() 7 | 8 | 9 | def parse_sidemenu(response): 10 | """ 11 | Convert the side menu to a dict keyed on app label, containing a list of links 12 | """ 13 | menu = defaultdict(list) 14 | current_app = "Global" 15 | soup = BeautifulSoup(response.content, "html.parser") 16 | 17 | for li in soup.find(id="jazzy-sidebar").find("ul").find_all("li"): 18 | if "nav-header" in li["class"]: 19 | current_app = li.text.strip() 20 | 21 | elif "nav-item" in li["class"]: 22 | href = li.find("a") 23 | menu[current_app].append(href["href"] if href else None) 24 | 25 | return menu 26 | 27 | 28 | def parse_topmenu(response): 29 | """ 30 | Convert the top menu to a list of dicts representing menus, items with submenus will have key 'children' 31 | """ 32 | menu = [] 33 | soup = BeautifulSoup(response.content, "html.parser") 34 | 35 | for li in soup.find(id="jazzy-navbar").find("ul").find_all("li"): 36 | anchor = li.find("a") 37 | 38 | # Skip brand link and menu button 39 | if isinstance(anchor.contents[0], Tag): 40 | continue 41 | 42 | item = {"name": anchor.text.strip(), "link": anchor["href"]} 43 | dropdown = li.find("div", class_="dropdown-menu") 44 | if dropdown: 45 | item["children"] = [{"name": a.text.strip(), "link": a["href"]} for a in dropdown.find_all("a")] 46 | 47 | menu.append(item) 48 | 49 | return menu 50 | 51 | 52 | def parse_usermenu(response): 53 | """ 54 | Convert the user menu to a list of dicts representing menus 55 | """ 56 | menu = [] 57 | soup = BeautifulSoup(response.content, "html.parser") 58 | 59 | for link in soup.find(id="jazzy-usermenu").find_all(["a", "form"]): 60 | item = {"name": link.text.strip(), "link": link.get("href") or link.get("action")} 61 | menu.append(item) 62 | 63 | return menu 64 | --------------------------------------------------------------------------------