django-vantage 0.1.0a1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_vantage-0.1.0a1/.gitignore +49 -0
- django_vantage-0.1.0a1/CHANGELOG.md +346 -0
- django_vantage-0.1.0a1/CODE_OF_CONDUCT.md +123 -0
- django_vantage-0.1.0a1/CONTRIBUTING.md +316 -0
- django_vantage-0.1.0a1/LICENSE +21 -0
- django_vantage-0.1.0a1/PKG-INFO +364 -0
- django_vantage-0.1.0a1/README.md +325 -0
- django_vantage-0.1.0a1/SECURITY.md +113 -0
- django_vantage-0.1.0a1/docs/accessibility.md +338 -0
- django_vantage-0.1.0a1/docs/analytics.md +366 -0
- django_vantage-0.1.0a1/docs/api.md +362 -0
- django_vantage-0.1.0a1/docs/browser-tests.md +83 -0
- django_vantage-0.1.0a1/docs/configuration.md +133 -0
- django_vantage-0.1.0a1/docs/deployment.md +325 -0
- django_vantage-0.1.0a1/docs/extending.md +349 -0
- django_vantage-0.1.0a1/docs/faq.md +273 -0
- django_vantage-0.1.0a1/docs/forms.md +689 -0
- django_vantage-0.1.0a1/docs/getting-started.md +229 -0
- django_vantage-0.1.0a1/docs/index.md +246 -0
- django_vantage-0.1.0a1/docs/inference.md +282 -0
- django_vantage-0.1.0a1/docs/internationalization.md +143 -0
- django_vantage-0.1.0a1/docs/lists.md +781 -0
- django_vantage-0.1.0a1/docs/pages-and-dashboards.md +455 -0
- django_vantage-0.1.0a1/docs/panels.md +540 -0
- django_vantage-0.1.0a1/docs/permissions.md +405 -0
- django_vantage-0.1.0a1/docs/security.md +336 -0
- django_vantage-0.1.0a1/docs/settings.md +350 -0
- django_vantage-0.1.0a1/docs/stylesheets/extra.css +89 -0
- django_vantage-0.1.0a1/docs/superpowers/specs/2026-08-13-list-page-decisions.md +266 -0
- django_vantage-0.1.0a1/docs/superpowers/specs/2026-08-13-platform-decisions.md +278 -0
- django_vantage-0.1.0a1/docs/superpowers/specs/2026-08-13-vantage-api-design.md +308 -0
- django_vantage-0.1.0a1/docs/tenancy.md +232 -0
- django_vantage-0.1.0a1/docs/theming.md +353 -0
- django_vantage-0.1.0a1/pyproject.toml +183 -0
- django_vantage-0.1.0a1/scripts/remaining.py +102 -0
- django_vantage-0.1.0a1/scripts/screenshots.py +144 -0
- django_vantage-0.1.0a1/scripts/verify_wheel.py +250 -0
- django_vantage-0.1.0a1/src/vantage/__init__.py +101 -0
- django_vantage-0.1.0a1/src/vantage/actions.py +325 -0
- django_vantage-0.1.0a1/src/vantage/api.py +724 -0
- django_vantage-0.1.0a1/src/vantage/apps.py +76 -0
- django_vantage-0.1.0a1/src/vantage/audit.py +405 -0
- django_vantage-0.1.0a1/src/vantage/auditviews.py +237 -0
- django_vantage-0.1.0a1/src/vantage/authviews.py +353 -0
- django_vantage-0.1.0a1/src/vantage/autocomplete.py +123 -0
- django_vantage-0.1.0a1/src/vantage/checks.py +798 -0
- django_vantage-0.1.0a1/src/vantage/color.py +261 -0
- django_vantage-0.1.0a1/src/vantage/concurrency.py +294 -0
- django_vantage-0.1.0a1/src/vantage/conf.py +242 -0
- django_vantage-0.1.0a1/src/vantage/contrib/__init__.py +18 -0
- django_vantage-0.1.0a1/src/vantage/contrib/django_admin.py +831 -0
- django_vantage-0.1.0a1/src/vantage/dashboards.py +1806 -0
- django_vantage-0.1.0a1/src/vantage/erd.py +210 -0
- django_vantage-0.1.0a1/src/vantage/export.py +130 -0
- django_vantage-0.1.0a1/src/vantage/filters.py +774 -0
- django_vantage-0.1.0a1/src/vantage/formviews.py +911 -0
- django_vantage-0.1.0a1/src/vantage/health.py +166 -0
- django_vantage-0.1.0a1/src/vantage/importer.py +1490 -0
- django_vantage-0.1.0a1/src/vantage/importviews.py +498 -0
- django_vantage-0.1.0a1/src/vantage/inference.py +286 -0
- django_vantage-0.1.0a1/src/vantage/inline.py +706 -0
- django_vantage-0.1.0a1/src/vantage/inlines.py +746 -0
- django_vantage-0.1.0a1/src/vantage/introspection.py +200 -0
- django_vantage-0.1.0a1/src/vantage/jobs.py +859 -0
- django_vantage-0.1.0a1/src/vantage/jobviews.py +187 -0
- django_vantage-0.1.0a1/src/vantage/layout.py +208 -0
- django_vantage-0.1.0a1/src/vantage/listprefs.py +1319 -0
- django_vantage-0.1.0a1/src/vantage/listprefsview.py +149 -0
- django_vantage-0.1.0a1/src/vantage/listquery.py +174 -0
- django_vantage-0.1.0a1/src/vantage/locale/ar/LC_MESSAGES/django.mo +0 -0
- django_vantage-0.1.0a1/src/vantage/locale/ar/LC_MESSAGES/django.po +4230 -0
- django_vantage-0.1.0a1/src/vantage/locale/ar/LC_MESSAGES/djangojs.mo +0 -0
- django_vantage-0.1.0a1/src/vantage/locale/ar/LC_MESSAGES/djangojs.po +575 -0
- django_vantage-0.1.0a1/src/vantage/locale/en/LC_MESSAGES/django.mo +0 -0
- django_vantage-0.1.0a1/src/vantage/locale/en/LC_MESSAGES/django.po +4406 -0
- django_vantage-0.1.0a1/src/vantage/locale/en/LC_MESSAGES/djangojs.mo +0 -0
- django_vantage-0.1.0a1/src/vantage/locale/en/LC_MESSAGES/djangojs.po +514 -0
- django_vantage-0.1.0a1/src/vantage/management/__init__.py +0 -0
- django_vantage-0.1.0a1/src/vantage/management/commands/__init__.py +0 -0
- django_vantage-0.1.0a1/src/vantage/management/commands/vantage_scaffold.py +55 -0
- django_vantage-0.1.0a1/src/vantage/media.py +784 -0
- django_vantage-0.1.0a1/src/vantage/middleware.py +437 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0001_initial.py +134 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0002_audit_log_and_saved_views.py +299 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0003_list_preferences.py +108 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0004_background_jobs.py +93 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0005_alter_vantagelogentry_action.py +27 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0006_nav_configuration.py +53 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0007_dashboard_layout.py +83 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0008_dashboardlayout_known_keys.py +17 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0009_navconfiguration_topbar.py +17 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0010_listpreference_column_widths_and_pinned.py +22 -0
- django_vantage-0.1.0a1/src/vantage/migrations/0011_navconfiguration_known_keys.py +17 -0
- django_vantage-0.1.0a1/src/vantage/migrations/__init__.py +0 -0
- django_vantage-0.1.0a1/src/vantage/models.py +1219 -0
- django_vantage-0.1.0a1/src/vantage/nav.py +1304 -0
- django_vantage-0.1.0a1/src/vantage/optimizer.py +62 -0
- django_vantage-0.1.0a1/src/vantage/pages.py +160 -0
- django_vantage-0.1.0a1/src/vantage/pagination.py +524 -0
- django_vantage-0.1.0a1/src/vantage/palette.py +394 -0
- django_vantage-0.1.0a1/src/vantage/panel_checks.py +264 -0
- django_vantage-0.1.0a1/src/vantage/panels.py +305 -0
- django_vantage-0.1.0a1/src/vantage/patterns.py +800 -0
- django_vantage-0.1.0a1/src/vantage/permissions.py +242 -0
- django_vantage-0.1.0a1/src/vantage/plugins.py +389 -0
- django_vantage-0.1.0a1/src/vantage/py.typed +0 -0
- django_vantage-0.1.0a1/src/vantage/records.py +1105 -0
- django_vantage-0.1.0a1/src/vantage/recordviews.py +466 -0
- django_vantage-0.1.0a1/src/vantage/registry.py +160 -0
- django_vantage-0.1.0a1/src/vantage/render.py +153 -0
- django_vantage-0.1.0a1/src/vantage/safety.py +144 -0
- django_vantage-0.1.0a1/src/vantage/savedviews.py +779 -0
- django_vantage-0.1.0a1/src/vantage/scaffold.py +84 -0
- django_vantage-0.1.0a1/src/vantage/scale.py +492 -0
- django_vantage-0.1.0a1/src/vantage/search.py +416 -0
- django_vantage-0.1.0a1/src/vantage/security.py +1013 -0
- django_vantage-0.1.0a1/src/vantage/serialize.py +385 -0
- django_vantage-0.1.0a1/src/vantage/settingsview.py +552 -0
- django_vantage-0.1.0a1/src/vantage/siteconfig.py +200 -0
- django_vantage-0.1.0a1/src/vantage/sites.py +110 -0
- django_vantage-0.1.0a1/src/vantage/slots.py +329 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/combobox.js +584 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/upload.js +249 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-audit.css +390 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-auth.css +225 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-dashboard.css +439 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-dashboard.js +189 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-editors.js +139 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-form.css +399 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-grid.css +612 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-grid.js +1170 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-i18n-fallback.js +58 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-import.css +313 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-inline.css +301 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-inline.js +803 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-inlines.css +271 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-inlines.js +225 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-jobs.css +164 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-jobs.js +140 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-listprefs.css +301 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-listprefs.js +119 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-palette.css +328 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-palette.js +532 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-settings.css +465 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-settings.js +443 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-topbar.css +199 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage-topbar.js +102 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage.css +2708 -0
- django_vantage-0.1.0a1/src/vantage/static/vantage/vantage.js +446 -0
- django_vantage-0.1.0a1/src/vantage/stats.py +997 -0
- django_vantage-0.1.0a1/src/vantage/summary.py +135 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/403.html +31 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/404.html +25 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/500.html +122 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/account.html +107 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/audit.html +190 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/base.html +182 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/bulk_edit.html +140 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/confirm_delete.html +87 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/dashboard.html +97 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/detail.html +74 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/form.html +136 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/import_map.html +136 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/import_preview.html +197 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/import_upload.html +91 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/jobs.html +114 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/list.html +464 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/logged_out.html +48 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/login.html +88 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/page.html +58 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/pages/health.html +33 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/pages/schema.html +69 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/analytics.html +76 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/brand.html +17 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/card_controls.html +37 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/card_editor.html +202 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/cell_link.html +11 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/chart_svg.html +47 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/conflict.html +55 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/field.html +53 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/filter_chips.html +35 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/filter_state.html +25 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/filters.html +98 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/grid_controls.html +150 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/history.html +92 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/inline_cell.html +28 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/inline_group.html +97 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/inline_row.html +126 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/job_progress.html +50 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/layout_node.html +69 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/list_prefs.html +444 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/list_toolbar.html +98 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/palette.html +62 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/related_block.html +59 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/row_actions.html +46 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/saved_views.html +178 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/stat_card.html +30 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/thumb.html +41 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/topbar.html +50 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/usermenu.html +139 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/partials/widget.html +138 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/password_change.html +54 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/search.html +84 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/settings.html +280 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/settings_nav.html +356 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/topbar.html +232 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/widgets/file.html +68 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/widgets/image.html +9 -0
- django_vantage-0.1.0a1/src/vantage/templates/vantage/widgets/search_select.html +25 -0
- django_vantage-0.1.0a1/src/vantage/templatetags/__init__.py +0 -0
- django_vantage-0.1.0a1/src/vantage/templatetags/vantage.py +117 -0
- django_vantage-0.1.0a1/src/vantage/templatetags/vantage_inline.py +84 -0
- django_vantage-0.1.0a1/src/vantage/templatetags/vantage_list.py +365 -0
- django_vantage-0.1.0a1/src/vantage/templatetags/vantage_slots.py +42 -0
- django_vantage-0.1.0a1/src/vantage/tenancy.py +1166 -0
- django_vantage-0.1.0a1/src/vantage/theme.py +148 -0
- django_vantage-0.1.0a1/src/vantage/topbar.py +679 -0
- django_vantage-0.1.0a1/src/vantage/topbarviews.py +270 -0
- django_vantage-0.1.0a1/src/vantage/urls.py +152 -0
- django_vantage-0.1.0a1/src/vantage/views.py +845 -0
- django_vantage-0.1.0a1/src/vantage/widgets.py +865 -0
- django_vantage-0.1.0a1/tests/__init__.py +0 -0
- django_vantage-0.1.0a1/tests/settings.py +58 -0
- django_vantage-0.1.0a1/tests/test_accessibility.py +772 -0
- django_vantage-0.1.0a1/tests/test_actions.py +292 -0
- django_vantage-0.1.0a1/tests/test_admin_adapter.py +722 -0
- django_vantage-0.1.0a1/tests/test_api.py +880 -0
- django_vantage-0.1.0a1/tests/test_audit.py +559 -0
- django_vantage-0.1.0a1/tests/test_auth_pages.py +248 -0
- django_vantage-0.1.0a1/tests/test_autocomplete.py +125 -0
- django_vantage-0.1.0a1/tests/test_branding.py +135 -0
- django_vantage-0.1.0a1/tests/test_browser.py +787 -0
- django_vantage-0.1.0a1/tests/test_checks.py +530 -0
- django_vantage-0.1.0a1/tests/test_color.py +209 -0
- django_vantage-0.1.0a1/tests/test_concurrency.py +439 -0
- django_vantage-0.1.0a1/tests/test_conf.py +70 -0
- django_vantage-0.1.0a1/tests/test_dashboards.py +1342 -0
- django_vantage-0.1.0a1/tests/test_detail.py +209 -0
- django_vantage-0.1.0a1/tests/test_erd.py +156 -0
- django_vantage-0.1.0a1/tests/test_export.py +150 -0
- django_vantage-0.1.0a1/tests/test_filter_ui.py +455 -0
- django_vantage-0.1.0a1/tests/test_filters.py +532 -0
- django_vantage-0.1.0a1/tests/test_forms.py +594 -0
- django_vantage-0.1.0a1/tests/test_grid_ui.py +271 -0
- django_vantage-0.1.0a1/tests/test_grouping.py +112 -0
- django_vantage-0.1.0a1/tests/test_health.py +113 -0
- django_vantage-0.1.0a1/tests/test_i18n.py +345 -0
- django_vantage-0.1.0a1/tests/test_import.py +885 -0
- django_vantage-0.1.0a1/tests/test_inference.py +314 -0
- django_vantage-0.1.0a1/tests/test_inline.py +619 -0
- django_vantage-0.1.0a1/tests/test_inlines.py +951 -0
- django_vantage-0.1.0a1/tests/test_introspection.py +190 -0
- django_vantage-0.1.0a1/tests/test_jobs.py +796 -0
- django_vantage-0.1.0a1/tests/test_layout.py +153 -0
- django_vantage-0.1.0a1/tests/test_listprefs.py +1111 -0
- django_vantage-0.1.0a1/tests/test_media.py +568 -0
- django_vantage-0.1.0a1/tests/test_middleware.py +328 -0
- django_vantage-0.1.0a1/tests/test_nav.py +953 -0
- django_vantage-0.1.0a1/tests/test_pages.py +178 -0
- django_vantage-0.1.0a1/tests/test_pagination.py +545 -0
- django_vantage-0.1.0a1/tests/test_palette.py +316 -0
- django_vantage-0.1.0a1/tests/test_panel_checks.py +95 -0
- django_vantage-0.1.0a1/tests/test_panel_resolution.py +111 -0
- django_vantage-0.1.0a1/tests/test_patterns.py +731 -0
- django_vantage-0.1.0a1/tests/test_permissions.py +188 -0
- django_vantage-0.1.0a1/tests/test_plugins.py +353 -0
- django_vantage-0.1.0a1/tests/test_records.py +1005 -0
- django_vantage-0.1.0a1/tests/test_registry.py +144 -0
- django_vantage-0.1.0a1/tests/test_release.py +154 -0
- django_vantage-0.1.0a1/tests/test_safety.py +194 -0
- django_vantage-0.1.0a1/tests/test_savedviews.py +756 -0
- django_vantage-0.1.0a1/tests/test_scaffold.py +131 -0
- django_vantage-0.1.0a1/tests/test_scale.py +534 -0
- django_vantage-0.1.0a1/tests/test_search.py +313 -0
- django_vantage-0.1.0a1/tests/test_security.py +1153 -0
- django_vantage-0.1.0a1/tests/test_settings_ui.py +329 -0
- django_vantage-0.1.0a1/tests/test_siteconfig.py +372 -0
- django_vantage-0.1.0a1/tests/test_slots.py +314 -0
- django_vantage-0.1.0a1/tests/test_smoke.py +348 -0
- django_vantage-0.1.0a1/tests/test_softdelete.py +191 -0
- django_vantage-0.1.0a1/tests/test_sorting.py +106 -0
- django_vantage-0.1.0a1/tests/test_stats.py +630 -0
- django_vantage-0.1.0a1/tests/test_stylesheets.py +120 -0
- django_vantage-0.1.0a1/tests/test_summary.py +148 -0
- django_vantage-0.1.0a1/tests/test_tenancy.py +1423 -0
- django_vantage-0.1.0a1/tests/test_theme.py +121 -0
- django_vantage-0.1.0a1/tests/test_topbar.py +147 -0
- django_vantage-0.1.0a1/tests/test_tree.py +114 -0
- django_vantage-0.1.0a1/tests/test_views.py +220 -0
- django_vantage-0.1.0a1/tests/test_widgets.py +802 -0
- django_vantage-0.1.0a1/tests/testapp/__init__.py +0 -0
- django_vantage-0.1.0a1/tests/testapp/apps.py +7 -0
- django_vantage-0.1.0a1/tests/testapp/models.py +478 -0
- django_vantage-0.1.0a1/tests/testapp/pages.py +36 -0
- django_vantage-0.1.0a1/tests/testapp/panel.py +43 -0
- django_vantage-0.1.0a1/tests/urls.py +7 -0
- django_vantage-0.1.0a1/tox.ini +99 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Project working memory — intentionally untracked
|
|
2
|
+
PLAN.md
|
|
3
|
+
HANDOFF.md
|
|
4
|
+
|
|
5
|
+
# Python
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*.egg-info/
|
|
9
|
+
.eggs/
|
|
10
|
+
build/
|
|
11
|
+
dist/
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
|
|
15
|
+
# Tooling
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.coverage
|
|
19
|
+
coverage.xml
|
|
20
|
+
htmlcov/
|
|
21
|
+
.mypy_cache/
|
|
22
|
+
.ty_cache/
|
|
23
|
+
.tox/
|
|
24
|
+
.nox/
|
|
25
|
+
|
|
26
|
+
# Node (contributor-only asset build)
|
|
27
|
+
node_modules/
|
|
28
|
+
|
|
29
|
+
# Local
|
|
30
|
+
.playwright-mcp/
|
|
31
|
+
*.sqlite3
|
|
32
|
+
.DS_Store
|
|
33
|
+
.env
|
|
34
|
+
|
|
35
|
+
# Translations
|
|
36
|
+
# `locale/**/*.mo` is deliberately NOT ignored — it stays committed alongside the
|
|
37
|
+
# `.po` it is compiled from. This project has no build hook that runs
|
|
38
|
+
# `compilemessages` on `pip install`, so an editable/source-checkout install (the
|
|
39
|
+
# thing a contributor and a downstream packager both do) would ship with no working
|
|
40
|
+
# Arabic until someone remembered a separate step. `pyproject.toml` also force-includes
|
|
41
|
+
# `*.mo` into the wheel via `artifacts`, independent of this file, so a later change
|
|
42
|
+
# here can't silently break translations in a *built* package either way. See
|
|
43
|
+
# docs/internationalization.md.
|
|
44
|
+
|
|
45
|
+
# Screenshots from browser-automation sessions; never part of the project.
|
|
46
|
+
.playwright-mcp/
|
|
47
|
+
|
|
48
|
+
# mkdocs build output
|
|
49
|
+
/site/
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
|
|
6
|
+
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
While the version is below `1.0` the public API may change between minor versions.
|
|
9
|
+
Anything that would be a breaking change after 1.0 is listed under **Changed** with the
|
|
10
|
+
word *breaking*, so the log is useful either way.
|
|
11
|
+
|
|
12
|
+
## [Unreleased]
|
|
13
|
+
|
|
14
|
+
## [0.1.0a1] — 2026-10-25
|
|
15
|
+
|
|
16
|
+
The first published pre-release. Everything below is new in it: the entries are
|
|
17
|
+
reconstructed from the commit history, which is the design record for this package and
|
|
18
|
+
worth reading directly — each commit explains why the shape is what it is and what was
|
|
19
|
+
rejected.
|
|
20
|
+
|
|
21
|
+
### Known limitations
|
|
22
|
+
|
|
23
|
+
Read these before deploying an alpha anywhere it matters.
|
|
24
|
+
|
|
25
|
+
- **The API is not frozen.** Attribute names, method signatures and settings keys may
|
|
26
|
+
change in any `0.x` release; breaking changes will be marked *breaking* below.
|
|
27
|
+
- **No WCAG 2.2 AA claim.** The three blockers the first audit named are fixed (see
|
|
28
|
+
*Fixed*), but the remaining findings and the lack of any screen-reader pass are
|
|
29
|
+
listed in [Accessibility](docs/accessibility.md#4-known-gaps).
|
|
30
|
+
- **The CSV importer stashes uploads on local disk.** Preview and commit must reach
|
|
31
|
+
the same filesystem: sticky sessions or a shared temp directory when running more
|
|
32
|
+
than one process. See [Deployment](docs/deployment.md#exports-stream-imports-are-capped).
|
|
33
|
+
- **Exports have no row ceiling.** They stream, so memory is flat, but a very large
|
|
34
|
+
table is exported in full.
|
|
35
|
+
- **Multiple sites share one settings dict.** Branding, `NAV` and the permission
|
|
36
|
+
resolver are global.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
#### The kernel
|
|
41
|
+
|
|
42
|
+
- `vantage.conf` — the `VANTAGE` settings dictionary, with defaults, derived values
|
|
43
|
+
(`SITE_ACRONYM` from `SITE_TITLE`, `LOGO_DARK` from `LOGO`) and loud rejection of
|
|
44
|
+
unknown keys with a did-you-mean suggestion. A typo must not silently produce a
|
|
45
|
+
default-coloured panel.
|
|
46
|
+
- `vantage.registry` — registration, auto-registration with app and model exclusion
|
|
47
|
+
patterns, and an `INCLUDE_ONLY` allowlist. Auto-registration never clobbers an
|
|
48
|
+
explicit panel.
|
|
49
|
+
- `vantage.panels.ModelPanel` — the full attribute surface, every value defaulting to
|
|
50
|
+
`None` meaning *infer*. Resolution is per attribute, which is the mechanism behind the
|
|
51
|
+
guarantee that setting `list_display` overrides the columns and nothing else.
|
|
52
|
+
- `vantage.checks` / `vantage.panel_checks` — field paths validated at `manage.py check`
|
|
53
|
+
time. Filters and search reject panel methods because they resolve in SQL;
|
|
54
|
+
`list_display` accepts them because it renders in Python.
|
|
55
|
+
- `vantage.introspection` — the single facade over `Model._meta`, encoding the three
|
|
56
|
+
documented traps: `ManyToOneRel`'s inverted flags, `GenericForeignKey` claiming
|
|
57
|
+
`many_to_one` while `related_model` is `None`, and auto-created through models storing
|
|
58
|
+
the owning class in `Meta.auto_created`.
|
|
59
|
+
- Autodiscovery via Django's `autodiscover_modules` contract, so a `panel.py` that raises
|
|
60
|
+
cannot leave the site half-registered.
|
|
61
|
+
|
|
62
|
+
#### Inference
|
|
63
|
+
|
|
64
|
+
- `vantage.inference` — pure functions, model in and configuration out, with no database,
|
|
65
|
+
request or settings access, which is what makes the engine table-testable.
|
|
66
|
+
`infer_list_link`, `infer_list_display`, `infer_list_filter`, `infer_list_search` and
|
|
67
|
+
`infer_ordering`. Sensitive field names (password, token, secret, api_key, hash…) are
|
|
68
|
+
never shown, searched or filtered.
|
|
69
|
+
- `vantage.widgets` — 24 `FieldKind`s mapping every Django field to a control, replacing
|
|
70
|
+
Django's 2005-era `formfield()` defaults: `type=email`, `type=url`, `type=number` with
|
|
71
|
+
step derived from `decimal_places`, `maxlength` from `max_length`, `accept` from
|
|
72
|
+
`FileExtensionValidator`, `pattern` on slugs. Django's `ModelForm` machinery is reused
|
|
73
|
+
wholesale; only the widget mapping is ours.
|
|
74
|
+
- `vantage.optimizer.plan_related` — `select_related`/`prefetch_related` derived from the
|
|
75
|
+
paths a page actually renders, so adding a column cannot reintroduce an N+1.
|
|
76
|
+
- `manage.py vantage_scaffold` — writes what inference decided out as an ordinary
|
|
77
|
+
`panel.py` you then own. `--write` refuses to clobber an existing file without
|
|
78
|
+
`--force`. The strongest test asserts the generated configuration passes the package's
|
|
79
|
+
own system checks.
|
|
80
|
+
- `vantage.patterns` — detectors for soft delete, hierarchy, timeline, publishing and
|
|
81
|
+
money, feeding trash views, tree rendering, date bucketing, inferred publish/unpublish
|
|
82
|
+
actions and currency formatting.
|
|
83
|
+
|
|
84
|
+
#### Theme and rendering
|
|
85
|
+
|
|
86
|
+
- `vantage.color` — full sRGB ⇄ OKLab ⇄ OKLCH conversion with binary-search gamut
|
|
87
|
+
clamping that gives up chroma rather than lightness. `accessible_pair` walks lightness
|
|
88
|
+
only as far as it must to reach 4.5:1. Contrast is asserted numerically across the
|
|
89
|
+
whole hue circle at 10-degree steps in both themes.
|
|
90
|
+
- `vantage.theme` — the token layer, adopting shadcn/ui's semantic-role token contract.
|
|
91
|
+
Neutrals are fixed; only brand-derived tokens vary with `BRAND_COLOR`.
|
|
92
|
+
- The panel shell: `base.html`, nav derived from the registry, the list page, the theme
|
|
93
|
+
toggle persisted to both `localStorage` and a cookie, distinguished empty states, and
|
|
94
|
+
icons inlined as SVG so a strict CSP is workable.
|
|
95
|
+
- Light, dark and system themes, and RTL, both from day one.
|
|
96
|
+
|
|
97
|
+
#### List page
|
|
98
|
+
|
|
99
|
+
- Validated column sorting with a primary-key tiebreaker appended to every sort, because
|
|
100
|
+
pagination over a column with duplicate values is otherwise unstable.
|
|
101
|
+
- `vantage.filters` — `ChoiceFilter`, `BooleanFilter`, `DateFilter`, `RelatedFilter` and
|
|
102
|
+
`NumericRangeFilter`, with counts off by default, CHEAP/COSTLY/NEVER classification, a
|
|
103
|
+
hard query budget, and the disjunctive self-exclusion rule so an unselected option
|
|
104
|
+
never falsely reads zero.
|
|
105
|
+
- `vantage.stats` — `Stat` and `Chart` declared in Python and computed against the
|
|
106
|
+
filtered queryset. Four stats cost one query; charts render as inline SVG whose
|
|
107
|
+
segments separate by lightness rather than hue, so a `BRAND_COLOR` change and the dark
|
|
108
|
+
theme both survive.
|
|
109
|
+
- `vantage.summary` — a per-column summary bar at the foot of every table, on by default
|
|
110
|
+
and needing no configuration. The whole bar is one `aggregate()` call. It declines to
|
|
111
|
+
compute what it would get wrong: identifiers stored as numbers, and anything reached
|
|
112
|
+
through a join.
|
|
113
|
+
- Streaming CSV, JSON (newline-delimited) and TSV export, all honouring the active
|
|
114
|
+
search, filters and sort, all `Cache-Control: no-store`.
|
|
115
|
+
- Time bucketing — day, week, month or year — computed from the rows already on the page
|
|
116
|
+
rather than a second grouped query.
|
|
117
|
+
- Hierarchy rendering for self-referential models, with mptt and treebeard ordering
|
|
118
|
+
handled natively and a plain self-FK arranged depth-first in Python.
|
|
119
|
+
- `vantage.listprefs` — per-list, per-user customisation from the UI: filters, facet
|
|
120
|
+
counts, the stat strip, charts, the summary bar, visible columns and their order, page
|
|
121
|
+
size and search fields. Resolution is UI override → `panel.py` → inference, with a
|
|
122
|
+
per-user row always beating the site-wide default. Switching a section off removes its
|
|
123
|
+
queries, not merely its markup.
|
|
124
|
+
|
|
125
|
+
#### Detail, forms and relations
|
|
126
|
+
|
|
127
|
+
- A read-only detail page showing fields the list omits by design, honouring
|
|
128
|
+
`get_queryset` so multi-tenancy hooks actually scope access.
|
|
129
|
+
- Bounded related-record previews — the first few rows with the child panel's own
|
|
130
|
+
columns, plus a count and a link through to the pre-filtered list. Five rows and a link
|
|
131
|
+
cost the same two queries whatever the count.
|
|
132
|
+
- Create, edit and delete, with a cascade-delete preview showing the real tree of what a
|
|
133
|
+
delete takes with it, counted.
|
|
134
|
+
- `vantage.layout` — the form layout DSL: `Tabs`, `Tab`, `Section`, `Row` as plain nested
|
|
135
|
+
Python. A field the layout forgets is appended rather than dropped; a field it names
|
|
136
|
+
that does not exist fails `manage.py check` (vantage.E017).
|
|
137
|
+
- Relation autocomplete: one endpoint for every model, with three guards — the target
|
|
138
|
+
must be registered, the view permission is checked against the target model, and
|
|
139
|
+
row-level `filter_queryset` applies. "Is there more" is answered by fetching one extra
|
|
140
|
+
row rather than a `COUNT`.
|
|
141
|
+
- `vantage.inline` and `vantage.concurrency` — inline cell editing with optimistic
|
|
142
|
+
concurrency.
|
|
143
|
+
|
|
144
|
+
#### Actions and bulk operations
|
|
145
|
+
|
|
146
|
+
- `@action` — ordinary panel methods with a decorator. `destructive`, `permission`,
|
|
147
|
+
`max_rows` and `confirm` are declared alongside.
|
|
148
|
+
- Selection travels as a predicate plus an exclusion set, never as a list of primary
|
|
149
|
+
keys, so selecting forty thousand rows costs the same as selecting three. The scope
|
|
150
|
+
actually resolved is always reported back in words.
|
|
151
|
+
- `vantage.models.VantageJob` — one row per bulk action too large to run inline.
|
|
152
|
+
|
|
153
|
+
#### Site-wide features
|
|
154
|
+
|
|
155
|
+
- Dashboard widgets: `StatCard`, `ChartCard`, `TableCard`, `ListCard` and `TemplateCard`,
|
|
156
|
+
on a four-column grid. `DefaultDashboard` means zero config still produces something
|
|
157
|
+
worth looking at. Widgets fail independently and are permission-gated *before* render,
|
|
158
|
+
so a widget over a forbidden model costs zero queries.
|
|
159
|
+
- Command palette (⌘K), global cross-model search, and a no-JS results page.
|
|
160
|
+
- Schema map derived from the registry, laid out server-side in Python, every node a
|
|
161
|
+
link.
|
|
162
|
+
- Custom pages: a class, a title and a `get_context` method, with the URL, nav entry and
|
|
163
|
+
rendering all defaulted, and a generic renderer for a page with no template.
|
|
164
|
+
- Declared navigation via `VANTAGE["NAV"]` — groups, order, labels, icons, badges, and
|
|
165
|
+
arbitrary links. `NAV_UNLISTED` defaults to `append` so a forgotten model still
|
|
166
|
+
appears.
|
|
167
|
+
- The audit log (`VantageLogEntry`) and its viewer.
|
|
168
|
+
- Saved views, with grants and per-user state.
|
|
169
|
+
- The CSV import wizard: upload, map columns, dry-run diff, commit.
|
|
170
|
+
- System health page — migrations, cache, database, task backend — superusers only.
|
|
171
|
+
- The in-panel settings screen: logo upload, brand colour, title and theme, editable by
|
|
172
|
+
a superuser with the database value overriding the file.
|
|
173
|
+
- Read-only mode and user impersonation, both enforced in the permission layer.
|
|
174
|
+
- `vantage.slots` and `vantage.plugins` — extension points.
|
|
175
|
+
- `vantage.contrib.django_admin` — an adapter for projects with existing
|
|
176
|
+
`contrib.admin` classes.
|
|
177
|
+
- `vantage-editors.js` — a dependency-free markdown toolbar for `richtext` fields,
|
|
178
|
+
degrading to the plain textarea it enhances. File upload drag-and-drop is a separate
|
|
179
|
+
feature, `upload.js`, wired through `vantage/widgets/file.html`.
|
|
180
|
+
|
|
181
|
+
#### Permissions
|
|
182
|
+
|
|
183
|
+
- Three concerns kept apart deliberately: model-level (may they see this section),
|
|
184
|
+
object-level (may they act on this row, N=1 only) and queryset-level (which rows may
|
|
185
|
+
they see, answered in bulk). `filter_queryset` exists so that a hundred-row page never
|
|
186
|
+
runs a hundred uncached `has_perm(perm, obj)` calls.
|
|
187
|
+
- `GuardianPermissions` for row scoping, using `get_objects_for_user` with
|
|
188
|
+
`accept_global_perms`. Opt-in, because whether object permissions should narrow the
|
|
189
|
+
admin is a policy decision.
|
|
190
|
+
- django-guardian, django-rules and django-simple-history are used if present, never
|
|
191
|
+
required.
|
|
192
|
+
|
|
193
|
+
#### Project infrastructure
|
|
194
|
+
|
|
195
|
+
- `example/` — a runnable "Northwind Supply" demo: 9 models covering the full spread of
|
|
196
|
+
field types and relation shapes, a seeded RNG, and 200 orders backdated over 180 days.
|
|
197
|
+
- Guards on the stylesheets themselves (`tests/test_stylesheets.py`): no physical
|
|
198
|
+
directions, so RTL keeps working from `dir="rtl"` alone; every colour from a token,
|
|
199
|
+
with a single deliberate exception for neutral shadows; and anything animating must
|
|
200
|
+
respect `prefers-reduced-motion`.
|
|
201
|
+
- CI over Python 3.12/3.13/3.14 × Django 5.2 LTS and 6.1, with Django `main` as an
|
|
202
|
+
allowed failure; a lint job; an advisory type-check job; and a build job that installs
|
|
203
|
+
the wheel into a clean virtualenv and renders a template out of it.
|
|
204
|
+
- `scripts/verify_wheel.py`, `tox.ini`, `.pre-commit-config.yaml`, `CONTRIBUTING.md`,
|
|
205
|
+
`SECURITY.md` and `CODE_OF_CONDUCT.md`.
|
|
206
|
+
- A documentation site at <https://pythondeveloper6.github.io/django-vantage/>, built
|
|
207
|
+
from `docs/` with MkDocs Material, checked with `--strict` on every pull request and
|
|
208
|
+
published from `main` by `.github/workflows/docs.yml`.
|
|
209
|
+
- A logo, and screenshots of the demo in both themes, regenerated by
|
|
210
|
+
`scripts/screenshots.py` from a pristine copy of the demo database.
|
|
211
|
+
|
|
212
|
+
### Changed
|
|
213
|
+
|
|
214
|
+
- The Django requirement is `>=5.2,<6.2`, and 6.0 joined the CI matrix. The bound
|
|
215
|
+
moves only when a new Django joins the matrix — see CONTRIBUTING's *Supported
|
|
216
|
+
versions*.
|
|
217
|
+
|
|
218
|
+
- Python floor raised to 3.12 — the intersection of Django 5.2 LTS and 6.x.
|
|
219
|
+
- *Breaking, pre-release:* `Section(title=...)` is keyword-only. The
|
|
220
|
+
leading-string-is-the-title convenience was ambiguous: a section titled "Publishing"
|
|
221
|
+
containing `status` was indistinguishable from a section containing the two fields
|
|
222
|
+
`title` and `body`.
|
|
223
|
+
- Inferred actions apply only to panels that declare none. Merging them into a declared
|
|
224
|
+
list meant a panel offering one action silently grew two more.
|
|
225
|
+
- `build_queryset` returns the unfiltered base alongside the filtered queryset, because
|
|
226
|
+
the facet engine needs the base to compute a disjunctive count.
|
|
227
|
+
- `dashboards.creation_field` no longer delegates to `detect_timeline`; they answer
|
|
228
|
+
different questions. The detector picks the best field to *group by* and prefers a
|
|
229
|
+
domain date, while "recent records" needs the date the row came into existence.
|
|
230
|
+
- Query-count tests assert that rendering five rows and two hundred and five rows cost
|
|
231
|
+
the same, with a ceiling, rather than asserting an exact number that legitimate
|
|
232
|
+
features move.
|
|
233
|
+
- Package metadata: the `htmx` and `tailwind` keywords are gone — neither is used
|
|
234
|
+
anywhere in the package — and the deprecated `License ::` classifier is dropped in
|
|
235
|
+
favour of the PEP 639 `license` expression. The sdist now carries `tests/` so
|
|
236
|
+
downstream packagers can run the suite.
|
|
237
|
+
|
|
238
|
+
### Fixed
|
|
239
|
+
|
|
240
|
+
#### In the release preparation
|
|
241
|
+
|
|
242
|
+
- The grid's "Keyboard shortcuts" switch now also silences `/` (it compared against a
|
|
243
|
+
value the grid never writes) and the inline editor's `e` (it never checked).
|
|
244
|
+
- An empty linked cell names its record to assistive technology instead of announcing
|
|
245
|
+
"link, dash", on the list grid, dashboard widgets and related blocks.
|
|
246
|
+
- `--input`, the form-field boundary, clears 3:1 against every surface in both themes;
|
|
247
|
+
it was 1.27:1 in light and translucent in dark.
|
|
248
|
+
- The FAQ, security and settings pages describe the CSP nonce and the security
|
|
249
|
+
settings as the code implements them.
|
|
250
|
+
- Every install, clone and advisory link names the real repository.
|
|
251
|
+
- `LOGO_DARK` is rendered: swapped in for the dark theme on the sidebar and both
|
|
252
|
+
sign-in screens. It was resolved and editable, and shown nowhere.
|
|
253
|
+
- With a `LOGO` set, the collapsed sidebar shows the acronym tile instead of nothing.
|
|
254
|
+
- `THEME_TOGGLE = False` now also ignores a theme a user saved before it was turned off.
|
|
255
|
+
- An unreadable `BRAND_COLOR` or `BRAND_RADIUS` is a `manage.py check` error
|
|
256
|
+
(`vantage.E004`, `vantage.E005`) instead of a failure on every page render.
|
|
257
|
+
- A trending stat on a list page compares with the period before the filtered one. The
|
|
258
|
+
list never passed the stats engine its unfiltered rows, so filtering on the trend's
|
|
259
|
+
own date field left nothing to compare with and every trend read as the whole total.
|
|
260
|
+
- The sidebar's dashboard item is highlighted only on the dashboard, not on every page
|
|
261
|
+
of a panel mounted below the site root.
|
|
262
|
+
- The grid's row checkboxes no longer render as "☐…".
|
|
263
|
+
- On Django 5.2, inlines no longer grow an extra column for the parent link. Before
|
|
264
|
+
Django 6.0 the inline formset appends that field to the list it is given, and the
|
|
265
|
+
list it was given was the one that also named the columns.
|
|
266
|
+
- A self-referencing model on the schema map's top row keeps its loop on the canvas.
|
|
267
|
+
|
|
268
|
+
#### Earlier
|
|
269
|
+
|
|
270
|
+
- The dashboard card cap was acting as an access rule: `DefaultDashboard` capped at
|
|
271
|
+
`MAX_DEFAULT_STATS` *before* filtering by permission, so a user who could see exactly
|
|
272
|
+
one model whose model sorted outside the first twelve was served an empty dashboard.
|
|
273
|
+
- `vantage.SiteConfiguration`, `VantageLogEntry`, `SavedView`, `SavedViewGrant`,
|
|
274
|
+
`SavedViewUserState` and `ListPreference` were auto-registering with Add/Edit/Delete
|
|
275
|
+
forms. An editable audit log is not an audit log, and a generic CRUD form for a saved
|
|
276
|
+
view routes around every permission rule in `savedviews.py`.
|
|
277
|
+
- Derived navigation listed custom pages without consulting `Page.has_permission`, so a
|
|
278
|
+
gated page appeared in the sidebar for users who could not open it. For a page gated
|
|
279
|
+
on something sensitive, the label itself is a disclosure.
|
|
280
|
+
- Audit hooks are placed relative to the transaction, not inside it: create and edit log
|
|
281
|
+
*outside* (catching a logging error inside an atomic block still marks it for
|
|
282
|
+
rollback), delete logs *before* (`Model.delete()` blanks the pk).
|
|
283
|
+
- `{% static %}` corrupted a URL the database layer had already resolved
|
|
284
|
+
(`/media/vantage/logo.svg` became `/static/media/vantage/logo.svg`). A new
|
|
285
|
+
`{% asset %}` tag passes resolved URLs through.
|
|
286
|
+
- The bulk-action `<form>` was never closed and ran to the end of the document,
|
|
287
|
+
swallowing the pagination. There is now a test asserting open/close parity.
|
|
288
|
+
- The bulk-selection column vanished when a parallel change re-indented the table; the
|
|
289
|
+
row checkbox now also carries the record's own label rather than a generic one.
|
|
290
|
+
- CSV import: encoding order is `utf-8-sig`, `utf-8`, `latin-1` — plain `utf-8` succeeds
|
|
291
|
+
on a BOM file and glues the BOM to the first header. Binary is rejected before
|
|
292
|
+
decoding, because `latin-1` decodes a PNG happily.
|
|
293
|
+
- CSV import: `CheckboxInput.value_from_datadict` reads the string `"0"` as `True`, and a
|
|
294
|
+
CSV that writes 1/0 is entirely normal; the blind spot is closed before the widget sees
|
|
295
|
+
the value.
|
|
296
|
+
- CSV import: foreign keys accept a label as well as a primary key, because the exporter
|
|
297
|
+
writes `str(obj)`. Ambiguous matches are an error rather than a coin flip.
|
|
298
|
+
- Combining `Sum('total')` with `Count('posts')` in a single `aggregate()` inflates
|
|
299
|
+
*both* through the join fan-out, not only the relational one. Stats are partitioned by
|
|
300
|
+
which multi-valued relation they touch, and a single stat spanning two raises rather
|
|
301
|
+
than lying.
|
|
302
|
+
- Messages were rendered per template, so a success message set before a redirect was
|
|
303
|
+
never displayed and would later surface on an unrelated screen. They now render in
|
|
304
|
+
`base.html`.
|
|
305
|
+
- URL ordering hazards: `add/` must precede the pk route, and because the pk converter is
|
|
306
|
+
`path:`, `edit/` and `delete/` must be declared before the bare detail route. Both are
|
|
307
|
+
asserted by a `resolve()` round trip.
|
|
308
|
+
- `@dataclass` installs its own `__init__` unconditionally, silently discarding the
|
|
309
|
+
custom constructors the layout containers need; they are `init=False` now.
|
|
310
|
+
- Light-dismiss on the column popover is capture-phase, because a bubbled click arriving
|
|
311
|
+
after the popover re-renders has a detached target.
|
|
312
|
+
- A missing `contenttypes` import in `models.py` had left the whole package unimportable.
|
|
313
|
+
- Three real contrast failures in hand-picked neutrals (light secondary text at 4.42:1,
|
|
314
|
+
the light success surface at 4.34:1, white on the dark destructive surface at 3.42:1),
|
|
315
|
+
all corrected by computing the required lightness.
|
|
316
|
+
- Inference: choice fields were offered as search targets (the column stores `draft`
|
|
317
|
+
while the user types `Draft`), search ties broke alphabetically rather than on
|
|
318
|
+
declaration order, and a `CharField(300)` was used as a column, which wrecks row
|
|
319
|
+
height.
|
|
320
|
+
|
|
321
|
+
### Security
|
|
322
|
+
|
|
323
|
+
- Sort parameters reach `order_by`, so they are never trusted: a value is dropped unless
|
|
324
|
+
it names a column currently in `list_display` **and** resolves to a concrete
|
|
325
|
+
single-valued field path. Without the `list_display` restriction the sort parameter is
|
|
326
|
+
an oracle for columns the panel deliberately does not expose.
|
|
327
|
+
- The autocomplete endpoint is a read API over arbitrary models; the target must be
|
|
328
|
+
registered, the view permission is checked against the *target* model rather than the
|
|
329
|
+
page the request came from, and row-level filtering applies.
|
|
330
|
+
- Declared navigation is presentation only. It reorders, renames and hides; it can never
|
|
331
|
+
grant access. Naming a model in `NAV` does not make it reachable.
|
|
332
|
+
- A relation whose model the user cannot view is omitted from the detail page entirely
|
|
333
|
+
rather than shown as a bare count — "this customer has 47 orders" is itself a leak.
|
|
334
|
+
- Read-only mode is enforced in the permission layer, before the superuser bypass,
|
|
335
|
+
because it is a statement about the deployment rather than about who is asking.
|
|
336
|
+
- Impersonation is superusers only, never onto another superuser, refused for inactive
|
|
337
|
+
accounts, and logged at warning level on both entry and exit.
|
|
338
|
+
- Permission-scoped exports are `Cache-Control: no-store`, so an extract does not sit in
|
|
339
|
+
a shared cache.
|
|
340
|
+
- Aggregate aliases are positional, so a user-supplied choice key can never become an
|
|
341
|
+
identifier.
|
|
342
|
+
- Sensitive field names are excluded from columns, filters, search, exports and audit
|
|
343
|
+
diffs.
|
|
344
|
+
|
|
345
|
+
[Unreleased]: https://github.com/Pythondeveloper6/django-vantage/compare/v0.1.0a1...HEAD
|
|
346
|
+
[0.1.0a1]: https://github.com/Pythondeveloper6/django-vantage/releases/tag/v0.1.0a1
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a
|
|
6
|
+
harassment-free experience for everyone, regardless of age, body size, visible or
|
|
7
|
+
invisible disability, ethnicity, sex characteristics, gender identity and expression,
|
|
8
|
+
level of experience, education, socio-economic status, nationality, personal appearance,
|
|
9
|
+
race, caste, colour, religion, or sexual identity and orientation.
|
|
10
|
+
|
|
11
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse,
|
|
12
|
+
inclusive, and healthy community.
|
|
13
|
+
|
|
14
|
+
## Our Standards
|
|
15
|
+
|
|
16
|
+
Examples of behaviour that contributes to a positive environment for our community
|
|
17
|
+
include:
|
|
18
|
+
|
|
19
|
+
* Demonstrating empathy and kindness toward other people
|
|
20
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
21
|
+
* Giving and gracefully accepting constructive feedback
|
|
22
|
+
* Accepting responsibility and apologising to those affected by our mistakes, and
|
|
23
|
+
learning from the experience
|
|
24
|
+
* Focusing on what is best not just for us as individuals, but for the overall community
|
|
25
|
+
|
|
26
|
+
Examples of unacceptable behaviour include:
|
|
27
|
+
|
|
28
|
+
* The use of sexualised language or imagery, and sexual attention or advances of any kind
|
|
29
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
30
|
+
* Public or private harassment
|
|
31
|
+
* Publishing others' private information, such as a physical or email address, without
|
|
32
|
+
their explicit permission
|
|
33
|
+
* Other conduct which could reasonably be considered inappropriate in a professional
|
|
34
|
+
setting
|
|
35
|
+
|
|
36
|
+
## Enforcement Responsibilities
|
|
37
|
+
|
|
38
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
|
39
|
+
acceptable behaviour and will take appropriate and fair corrective action in response to
|
|
40
|
+
any behaviour that they deem inappropriate, threatening, offensive, or harmful.
|
|
41
|
+
|
|
42
|
+
Community leaders have the right and responsibility to remove, edit, or reject comments,
|
|
43
|
+
commits, code, wiki edits, issues, and other contributions that are not aligned to this
|
|
44
|
+
Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
|
45
|
+
|
|
46
|
+
## Scope
|
|
47
|
+
|
|
48
|
+
This Code of Conduct applies within all community spaces — the issue tracker, pull
|
|
49
|
+
requests, discussions, and the commit history — and also applies when an individual is
|
|
50
|
+
officially representing the community in public spaces. Examples of representing our
|
|
51
|
+
community include using an official email address, posting via an official social media
|
|
52
|
+
account, or acting as an appointed representative at an online or offline event.
|
|
53
|
+
|
|
54
|
+
## Enforcement
|
|
55
|
+
|
|
56
|
+
Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported to
|
|
57
|
+
the maintainers responsible for enforcement at:
|
|
58
|
+
|
|
59
|
+
**<pythondeveloper6@gmail.com>**
|
|
60
|
+
|
|
61
|
+
All complaints will be reviewed and investigated promptly and fairly. All community
|
|
62
|
+
leaders are obligated to respect the privacy and security of the reporter of any
|
|
63
|
+
incident.
|
|
64
|
+
|
|
65
|
+
## Enforcement Guidelines
|
|
66
|
+
|
|
67
|
+
Community leaders will follow these Community Impact Guidelines in determining the
|
|
68
|
+
consequences for any action they deem in violation of this Code of Conduct:
|
|
69
|
+
|
|
70
|
+
### 1. Correction
|
|
71
|
+
|
|
72
|
+
**Community Impact**: Use of inappropriate language or other behaviour deemed
|
|
73
|
+
unprofessional or unwelcome in the community.
|
|
74
|
+
|
|
75
|
+
**Consequence**: A private, written warning from community leaders, providing clarity
|
|
76
|
+
around the nature of the violation and an explanation of why the behaviour was
|
|
77
|
+
inappropriate. A public apology may be requested.
|
|
78
|
+
|
|
79
|
+
### 2. Warning
|
|
80
|
+
|
|
81
|
+
**Community Impact**: A violation through a single incident or series of actions.
|
|
82
|
+
|
|
83
|
+
**Consequence**: A warning with consequences for continued behaviour. No interaction with
|
|
84
|
+
the people involved, including unsolicited interaction with those enforcing the Code of
|
|
85
|
+
Conduct, for a specified period of time. This includes avoiding interactions in community
|
|
86
|
+
spaces as well as external channels like social media. Violating these terms may lead to
|
|
87
|
+
a temporary or permanent ban.
|
|
88
|
+
|
|
89
|
+
### 3. Temporary Ban
|
|
90
|
+
|
|
91
|
+
**Community Impact**: A serious violation of community standards, including sustained
|
|
92
|
+
inappropriate behaviour.
|
|
93
|
+
|
|
94
|
+
**Consequence**: A temporary ban from any sort of interaction or public communication
|
|
95
|
+
with the community for a specified period of time. No public or private interaction with
|
|
96
|
+
the people involved, including unsolicited interaction with those enforcing the Code of
|
|
97
|
+
Conduct, is allowed during this period. Violating these terms may lead to a permanent
|
|
98
|
+
ban.
|
|
99
|
+
|
|
100
|
+
### 4. Permanent Ban
|
|
101
|
+
|
|
102
|
+
**Community Impact**: Demonstrating a pattern of violation of community standards,
|
|
103
|
+
including sustained inappropriate behaviour, harassment of an individual, or aggression
|
|
104
|
+
toward or disparagement of classes of individuals.
|
|
105
|
+
|
|
106
|
+
**Consequence**: A permanent ban from any sort of public interaction within the
|
|
107
|
+
community.
|
|
108
|
+
|
|
109
|
+
## Attribution
|
|
110
|
+
|
|
111
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1,
|
|
112
|
+
available at
|
|
113
|
+
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
|
114
|
+
|
|
115
|
+
Community Impact Guidelines were inspired by
|
|
116
|
+
[Mozilla's code of conduct enforcement ladder][mozilla].
|
|
117
|
+
|
|
118
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
|
119
|
+
https://www.contributor-covenant.org/faq. Translations are available at
|
|
120
|
+
https://www.contributor-covenant.org/translations.
|
|
121
|
+
|
|
122
|
+
[homepage]: https://www.contributor-covenant.org
|
|
123
|
+
[mozilla]: https://github.com/mozilla/inclusion
|