Compare commits

...

13 commits

Author SHA1 Message Date
12f0314b76
nested inline is shit
All checks were successful
Build and Deploy / build (push) Successful in 38s
Build and Deploy / deploy (push) Successful in 4s
2025-03-07 15:37:22 +01:00
0c83c0cfe8
only display offering when there is a description 2025-03-07 15:21:09 +01:00
d87929f6b4
drag drop ordering for faqs 2025-03-07 14:58:51 +01:00
b45c725c1a
use better admin theme 2025-03-07 14:55:22 +01:00
4e1f0f962b
use nested admin for simpler plan admin 2025-03-07 14:50:36 +01:00
9aaaa90d1a
include updated version of flyer 2025-03-07 14:50:10 +01:00
3c08d4c293
add about page 2025-03-07 10:53:07 +01:00
eb5e4b0534
define inlines for easier record editing 2025-03-06 16:50:36 +01:00
d3d5409452
new open graph image 2025-03-06 15:06:44 +01:00
de87de7680
update title 2025-03-06 14:58:32 +01:00
99d0128053
direct link to services on listing 2025-03-06 13:52:07 +01:00
46e844861e
add scroll padding and improved title 2025-03-06 13:46:38 +01:00
a5fde42132
make offering more clear 2025-03-06 13:13:18 +01:00
19 changed files with 352 additions and 31 deletions

View file

@ -1,5 +1,7 @@
from django.contrib import admin
from django.utils.html import format_html
from adminsortable2.admin import SortableAdminMixin
from .models import (
Category,
CloudProvider,
@ -15,6 +17,40 @@ from .models import (
)
class PlanInline(admin.StackedInline):
model = Plan
extra = 1
fieldsets = (
(None, {"fields": ("name", "description", "pricing", "plan_description")}),
)
class ExternalLinkOfferingInline(admin.TabularInline):
model = ExternalLinkOffering
extra = 1
fields = ("description", "url", "order")
ordering = ("order", "description")
class OfferingInline(admin.StackedInline):
model = ServiceOffering
extra = 1
fieldsets = (
(
None,
{
"fields": (
"description",
"service",
"cloud_provider",
"offer_description",
)
},
),
)
show_change_link = True
@admin.register(ReusableText)
class ReusableTextAdmin(admin.ModelAdmin):
list_display = ("name",)
@ -36,6 +72,7 @@ class CloudProviderAdmin(admin.ModelAdmin):
list_display = ("name", "slug", "logo_preview")
search_fields = ("name", "description")
prepopulated_fields = {"slug": ("name",)}
inlines = [OfferingInline]
def logo_preview(self, obj):
if obj.logo:
@ -61,7 +98,7 @@ class ServiceAdmin(admin.ModelAdmin):
search_fields = ("name", "description", "slug")
prepopulated_fields = {"slug": ("name",)}
filter_horizontal = ("categories",)
inlines = [ExternalLinkInline]
inlines = [ExternalLinkInline, OfferingInline]
def logo_preview(self, obj):
if obj.logo:
@ -83,21 +120,6 @@ class ServiceAdmin(admin.ModelAdmin):
partner_list.short_description = "Consulting Partners"
class PlanInline(admin.StackedInline):
model = Plan
extra = 1
fieldsets = (
(None, {"fields": ("name", "description", "pricing", "plan_description")}),
)
class ExternalLinkOfferingInline(admin.TabularInline):
model = ExternalLinkOffering
extra = 1
fields = ("description", "url", "order")
ordering = ("order", "description")
@admin.register(ServiceOffering)
class ServiceOfferingAdmin(admin.ModelAdmin):
list_display = ("service", "cloud_provider")
@ -130,7 +152,7 @@ class LeadAdmin(admin.ModelAdmin):
@admin.register(WebsiteFaq)
class WebsiteFaqAdmin(admin.ModelAdmin):
class WebsiteFaqAdmin(SortableAdminMixin, admin.ModelAdmin):
list_display = ("question", "order")
search_fields = ("question", "answer")
ordering = ("order",)

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

View file

@ -0,0 +1,214 @@
{% extends 'services/base.html' %}
{% load static %}
{% load contact_tags %}
{% block title %}About Open Cloud Native Services Hub{% endblock %}
{% block content %}
<section class="section bg-primary-subtle">
<div class="container mx-auto px-20 px-lg-0 pt-40 pb-60">
<header class="section-primary__header text-center">
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">About Servala</h2>
<div class="text-gray-300 w-lg-37 mx-auto">
<p class="mb-0">Open Cloud Native Service Hub. Unlock the Power of Cloud Native Applications.</p>
</div>
</header>
</div>
</section>
<section class="section">
<div class="container mx-auto px-20 px-lg-0 pt-80 pb-40">
<div class="page-content w-lg-72 mx-auto">
<div class="d-lg-flex pb-60">
<div class="flex-1 pr-lg-50 d-lg-flex flex-column justify-content-between mb-60 mb-lg-0">
<div>
<header>
<h2 class="fs-32 fw-semibold mb-12">Overview</h2>
</header>
<div class="text-gray-500 fs-19 lh-1-7">
<p>Servala connects businesses, developers, and cloud service providers on one unique hub with secure, scalable, and easy-to-use cloud-native services.</p>
<p>With Servala, businesses can seamlessly access and deploy a vast range of software, databases, applications, and DevOps tools such as PostgreSQL, Red Hat OpenShift, Keycloak, GitLab or Forgejo across multiple cloud providers and regions. This ensures businesses can seamlessly access and deploy services, applications, and DevOps tools across different cloud environments without being tied to a single provider.</p>
<p>With Servala, businesses can stay agile, avoid vendor lock-in, optimize cloud costs, and ensure security and compliance. For Independent Software Vendors (ISVs), Servala opens up additional channels to offer their software products. At the same time, Cloud Service Providers (CSPs) can add value on top of their existing core offerings (compute, storage, network).</p>
</div>
</div>
<div class="page-action">
<a class="btn btn-primary btn-lg mr-md-17 mb-17 mb-md-0px mb-lg-17 mb-xl-0 w-100 w-md-auto" href="{% static "servala-flyer.pdf" %}" role="button">Download Flyer</a>
<a class="btn btn-outline btn-lg w-100 w-md-auto" href="{% url 'services:service_list' %}" role="button">Discover Services</a>
</div>
</div>
<div class="w-lg-30">
<div class="page-header__image-wrapper">
<img class="page-header__image" src="{% static "img/about-image.png" %}" alt="About Servala">
</div>
</div>
</div>
<div>
<h2 class="fs-32 fw-semibold mt-3">Who benefits from using Servala?</h2>
<div class="text-gray-500 fs-19 lh-1-7">
<p>Servala is designed for CSPs, ISVs, and Enterprises and their users, enabling them to offer, integrate, and consume cloud-native services and applications and DevOps tools with ease. It bridges the gap between CSPs seeking value-added services, ISVs looking to distribute and monetize their applications and services, and Enterprises needing scalable, secure, and cost-efficient cloud solutions and their users who need to access those services easily - all within an open, cloud-agnostic ecosystem.</p>
</div>
<article class="pt-20">
<h3 class="fs-24 fw-semibold">Independent Software Vendors (ISVs)</h3>
<ul class="list-disc pl-8 text-gray-500 fs-19">
<li>Transform applications into SaaS offerings.</li>
<li>Leverage the Servala Hub to distribute, monetize, and efficiently operate your software.</li>
<li>Extend your reach to new markets and ecosystems.</li>
</ul>
</article>
<article class="pt-20">
<h3 class="fs-24 fw-semibold">Cloud Service Providers (CSPs)</h3>
<ul class="list-disc pl-8 text-gray-500 fs-19">
<li>Offer value-added services and applications to end users.</li>
<li>Respond effectively to fast-paced market changes.</li>
<li>Gain tools to enhance operational efficiency and market relevance.</li>
</ul>
</article>
<article class="pt-20">
<h3 class="fs-24 fw-semibold">Enterprises and Their Users</h3>
<ul class="list-disc pl-8 text-gray-500 fs-19">
<li>Access scalable, secure, and cost-efficient services.</li>
<li>Enable self-service installation of trusted applications without managing infrastructure.</li>
<li>Benefit from built-in compliance, developer productivity boosts, and operational simplicity.</li>
</ul>
</article>
</div>
<div>
<h2 class="fs-32 fw-semibold mt-5">Why Choose Servala?</h2>
<div class="row row-cols-1 row-cols-md-3 g-4 pt-3">
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-lightning-charge-fill fs-2 text-primary me-3"></i>
<h3 class="fs-24 fw-semibold card-title mb-0">Agility &amp; Faster Time-to-Market</h3>
</div>
<p class="text-gray-500 fs-19 card-text">Access a vast catalog of services and applications for rapid deployment and
innovation.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-cloud-check-fill fs-2 text-primary me-3"></i>
<h3 class="fs-24 fw-semibold card-title mb-0">Cloud-Agnostic &amp; Vendor-Independent</h3>
</div>
<p class="text-gray-500 fs-19 card-text">Deploy services on any cloud or on-premises, ensuring maximum
flexibility.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-shield-check fs-2 text-primary me-3"></i>
<h3 class="fs-24 fw-semibold card-title mb-0">Secure &amp; Compliant</h3>
</div>
<p class="text-gray-500 fs-19 card-text">Built to meet rigorous industry standards (GDPR, ISO, ISAE) to ensure data
protection and regulatory compliance.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-cash-coin fs-2 text-primary me-3"></i>
<h3 class="fs-24 fw-semibold card-title mb-0">Cost Optimization</h3>
</div>
<p class="text-gray-500 fs-19 card-text">Transparent pricing to manage and reduce cloud expenses efficiently.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-puzzle-fill fs-2 text-primary me-3"></i>
<h3 class="fs-24 fw-semibold card-title mb-0">Seamless Integration</h3>
</div>
<p class="text-gray-500 fs-19 card-text">Pre-configured solutions and Kubernetes-native tools integrate smoothly into
existing workflows.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-graph-up-arrow fs-2 text-primary me-3"></i>
<h3 class="fs-24 fw-semibold card-title mb-0">Scalable &amp; DevOps-Ready</h3>
</div>
<p class="text-gray-500 fs-19 card-text">Cloud-native services that scale automatically, keeping up with your business
growth.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-gear-wide-connected fs-2 text-primary me-3"></i>
<h3 class="fs-24 fw-semibold card-title mb-0">Fully Managed &amp; Hassle-Free Operations</h3>
</div>
<p class="text-gray-500 fs-19 card-text">VSHN takes care of maintenance, monitoring, and updates - so you can focus on
innovation.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-code-square fs-2 text-primary me-3"></i>
<h3 class="fs-24 fw-semibold card-title mb-0">Open Source &amp; Beyond</h3>
</div>
<p class="text-gray-500 fs-19 card-text">Access both Open Source and commercial editions to suit your needs.</p>
</div>
</div>
</div>
<div class="col">
<div class="card h-100 shadow-sm">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<i class="bi bi-people-fill fs-2 text-primary me-3"></i>
<h3 class="fs-24 fw-semibold card-title mb-0">Expert Network &amp; Consulting</h3>
</div>
<p class="text-gray-500 fs-19 card-text">Tap into a network of consulting partners who understand and optimize available
services.</p>
</div>
</div>
</div>
</div>
</div>
<div class="d-lg-flex mt-5">
<div class="flex-1 pr-lg-50 d-lg-flex flex-column justify-content-between mb-60 mb-lg-0">
<div>
<h2 class="fs-32 fw-semibold mb-12">Our Mascot</h2>
<div class="text-gray-500 fs-19 lh-1-7">
<p>Say Hi! to Sir Vala 👋</p>
<p>Did you know? The <a href="https://en.wikipedia.org/wiki/Serval" target="_blank">serval (Leptailurus serval)</a> is a wild cat native to Africa, found in grasslands, wetlands, and forests across sub-Saharan regions. It is protected in many areas, with hunting regulated or prohibited.</p>
</div>
</div>
</div>
<div class="w-lg-30">
<div class="page-header__image-wrapper">
<img class="page-header__image" src="{% static "img/sir-vala-text.png" %}" alt="Servala Mascot Sir Vala">
</div>
</div>
</div>
<div>
<h2 class="fs-32 fw-semibold mt-5">Contact Us</h2>
{% embedded_contact_form source="About Us" %}
</div>
</div>
</div>
</section>
{% endblock %}

View file

@ -41,6 +41,7 @@
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:service_list' %}">Services</a></li>
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:provider_list' %}">Cloud Providers</a></li>
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:partner_list' %}">Consulting Partners</a></li>
<li class="menu__item"><a class="menu__item-link" href="{% url 'services:about' %}">About</a></li>
</ul>
<ul class="menu-cta mb-0">
<li class="mr-17"><a class="btn btn-outline-light btn-outline-primary" href="{% url 'services:contact' %}" role="button">Contact</a></li>
@ -129,6 +130,7 @@
<h4 class="fs-base fw-semibold">Contents</h4>
<ul class="list-unstyled space-y-20 fs-15 fw-medium ps-0">
<li><a href="{% url 'services:homepage' %}">Home</a></li>
<li><a href="{% url 'services:about' %}">About</a></li>
<li><a href="{% url 'services:service_list' %}">Services</a></li>
<li><a href="{% url 'services:provider_list' %}">Cloud Providers</a></li>
<li><a href="{% url 'services:partner_list' %}">Consulting Partners</a></li>

View file

@ -1,4 +1,5 @@
{% extends 'services/base.html' %}
{% load static %}
{% block title %}{{ offering.service.name }} on {{ offering.cloud_provider.name }}{% endblock %}
@ -8,7 +9,7 @@
<header class="section-primary__header text-center">
<h2 class="section-h1 fs-40 fs-lg-64 mb-24">Service Offering</h2>
<div class="text-gray-300 w-lg-37 mx-auto">
<p class="mb-0">{{ offering.service.name }} on {{ offering.cloud_provider.name }}</p>
<p class="mb-0">{{ offering.service.name }} managed by VSHN on {{ offering.cloud_provider.name }}</p>
</div>
</header>
</div>
@ -30,6 +31,20 @@
{% endif %}
</div>
<div class="mb-40">
<h3 class="fw-semibold mb-12">Managed by</h3>
<a href="https://www.vshn.ch/" target="_blank">
<img class="img-fluid" src="{% static "img/vshn-logo-wide.png" %}" alt="VSHN logo" style="max-height: 40px;">
</a>
</div>
<div class="mb-40">
<h3 class="fw-semibold mb-12">Runs on</h3>
<a href="{{ offering.cloud_provider.get_absolute_url }}">
<img class="img-fluid" src="{{ offering.cloud_provider.logo.url }}" alt="{{ offering.cloud_provider.name }} logo" style="max-height: 40px;">
</a>
</div>
<!-- External Links for Offering -->
{% if offering.external_links.exists %}
<div class="mb-40">
@ -56,6 +71,7 @@
{% if offering.service.consulting_partners.exists %}
<div class="mb-40">
<h3 class="fw-semibold mb-12">Consulting Partners</h3>
<p>If you want to get the most out of your managed {{ offering.service.name }}, our consulting partners can help you optimize your setup and application:</p>
<ul class="list-unstyled space-y-12 fs-19 ps-0">
{% for partner in offering.service.consulting_partners.all %}
<li>
@ -81,26 +97,25 @@
<!-- Header -->
<div class="pt-60 pb-lg-60 w-lg-70">
<header>
{% if offering.cloud_provider.logo %}
<p class="mb-6"><a href="{{ offering.cloud_provider.get_absolute_url }}">
<img class="img-fluid" src="{{ offering.cloud_provider.logo.url }}"
alt="{{ offering.cloud_provider.name }} logo" style="max-height: 40px;"></a>
</p>
{% endif %}
<h2 class="fs-50 fw-semibold lh-1 mb-12"><a href="{{ offering.service.get_absolute_url }}" class="text-decoration-none">{{ offering.service.name }}</a></h2>
<h2 class="fs-50 fw-semibold lh-1 mb-12"><a href="{{ offering.service.get_absolute_url }}" class="text-decoration-none">Managed {{ offering.service.name }}</a></h2>
</header>
<div class="fs-19 text-gray-500">
{% for category in offering.service.categories.all %}
<button class="btn btn-tertiary btn-sm mr-12">{{ category.full_path }}</button>
{% endfor %}
<button class="btn btn-tertiary btn-sm mr-12">Managed by VSHN</button>
<button class="btn btn-tertiary btn-sm mr-12">Running on {{ offering.cloud_provider.name }}</button>
</div>
{% if offering.short_description %}
<div class="fs-19 text-gray-500">
{{ offering.short_description|safe }}
</div>
{% endif %}
</div>
<!-- Service Description -->
{% if offering.service.description %}
<!-- Service Overview -->
<div>
<h3 class="fs-24 fw-semibold lh-1 mb-12">Service Overview</h3>
<div class="fs-19 text-gray-500">
@ -109,6 +124,7 @@
</div>
{% endif %}
{% if offering.offer_description or offering.description %}
<!-- Offering Description -->
<div class="pt-40 pt-lg-34">
<h3 class="fs-24 fw-semibold lh-1 mb-12">Offering</h3>
@ -123,9 +139,10 @@
</div>
{% endif %}
</div>
{% endif %}
<!-- Plans -->
<div class="pt-24" id="plans">
<div class="pt-24" id="plans" style="scroll-margin-top: 100px;">
<h3 class="fs-24 fw-semibold lh-1 mb-12">Available Plans</h3>
<div class="row">
{% for plan in offering.plans.all %}

View file

@ -143,7 +143,7 @@
<!-- Services -->
{% if services %}
<div class="pt-40">
<h3 class="fs-24 fw-semibold lh-1 mb-12">Consulting for Services</h3>
<h3 class="fs-24 fw-semibold lh-1 mb-12" id="services" style="scroll-margin-top: 100px;">Consulting for Services</h3>
<div class="row">
{% for service in services %}
<div class="col-12 col-md-6 mb-30">

View file

@ -131,6 +131,7 @@
{% if partner.website %}
<a href="{{ partner.website }}" class="btn btn-primary btn-sm" target="_blank">Visit Website</a>
{% endif %}
<a href="{{ partner.get_absolute_url }}#services" class="btn btn-primary btn-sm">Available Services</a>
</div>
</div>
</div>

View file

@ -143,7 +143,7 @@
<!-- Services -->
{% if services %}
<div class="pt-40">
<h3 class="fs-24 fw-semibold lh-1 mb-12">Available Services</h3>
<h3 class="fs-24 fw-semibold lh-1 mb-12" id="services" style="scroll-margin-top: 100px;">Available Services</h3>
<div class="row">
{% for offering in provider.offerings.all %}
<div class="col-12 col-md-6 mb-30">

View file

@ -114,6 +114,7 @@
{% if provider.website %}
<a href="{{ provider.website }}" class="btn btn-primary btn-sm" target="_blank">Visit Website</a>
{% endif %}
<a href="{{ provider.get_absolute_url }}#services" class="btn btn-primary btn-sm">Available Services</a>
</div>
</div>
</div>

View file

@ -5,6 +5,7 @@ app_name = "services"
urlpatterns = [
path("", views.homepage, name="homepage"),
path("about/", views.about, name="about"),
path("offerings/", views.offering_list, name="offering_list"),
path("providers/", views.provider_list, name="provider_list"),
path("partners/", views.partner_list, name="partner_list"),

View file

@ -22,4 +22,8 @@ def homepage(request):
"websitefaqs": websitefaqs,
}
return render(request, "services/homepage.html", context)
return render(request, "pages/homepage.html", context)
def about(request):
return render(request, "pages/about.html")

View file

@ -58,6 +58,7 @@ WEBSITE_URL = env.str("WEBSITE_URL", default="https://serva.la")
# Application definition
INSTALLED_APPS = [
"jazzmin",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
@ -69,6 +70,8 @@ INSTALLED_APPS = [
"django_prose_editor",
"rest_framework",
"schema_viewer",
"nested_admin",
"adminsortable2",
# local
"hub.services",
"hub.broker",

View file

@ -6,6 +6,9 @@ readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"django>=5.1.5",
"django-admin-sortable2>=2.2.4",
"django-jazzmin>=3.0.1",
"django-nested-admin>=4.1.1",
"django-prose-editor[sanitize]>=0.10.3",
"django-schema-viewer>=0.5.2",
"djangorestframework>=3.15.2",

53
uv.lock generated
View file

@ -1,4 +1,5 @@
version = 1
revision = 1
requires-python = ">=3.13"
[[package]]
@ -46,6 +47,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/11/e6/e92c8c788b83d109f34d933c5e817095d85722719cb4483472abc135f44e/Django-5.1.5-py3-none-any.whl", hash = "sha256:c46eb936111fffe6ec4bc9930035524a8be98ec2f74d8a0ff351226a3e52f459", size = 8276957 },
]
[[package]]
name = "django-admin-sortable2"
version = "2.2.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ee/a1/0651ad69906f9ec9e73897353e933611550c6d31bfa9f721319c0ed99108/django_admin_sortable2-2.2.4.tar.gz", hash = "sha256:155e6114c7a931bceed9513af014f782ff1e643d99e81ddfef934f1daecd669d", size = 68207 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/66/c3/e804b1f04546c1060e566f35177c346590820a95bfb981d1f6360b419437/django_admin_sortable2-2.2.4-py3-none-any.whl", hash = "sha256:406c5b6d6e84ad982cc6e53c3f34b5db5f0a3f34891126af90c9fb2c372f53d5", size = 90816 },
]
[[package]]
name = "django-browser-reload"
version = "1.17.0"
@ -68,6 +81,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/48/90/01755e4a42558b763f7021e9369aa6aa94c2ede7313deed56cb7483834ab/django_cache_url-3.4.5-py2.py3-none-any.whl", hash = "sha256:5f350759978483ab85dc0e3e17b3d53eed3394a28148f6bf0f53d11d0feb5b3c", size = 4760 },
]
[[package]]
name = "django-jazzmin"
version = "3.0.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
]
sdist = { url = "https://files.pythonhosted.org/packages/84/96/21b6255e90d92a3eb4e93bea9376635d54258e0353ebb913a55e40ae9254/django_jazzmin-3.0.1.tar.gz", hash = "sha256:67ae148bade41267a09ca8e4352ddefa6121795ebbac238bb9a6564ff841eb1b", size = 2053550 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ad/5b/2f8c4b168e6c41bf1e4b14d787deb23d80f618f0693db913bbe208a4a907/django_jazzmin-3.0.1-py3-none-any.whl", hash = "sha256:12a0a4c1d4fd09c2eef22acf6a1f03112b515ba695c59faa8ea80efc81c1f21b", size = 2125957 },
]
[[package]]
name = "django-js-asset"
version = "3.0.1"
@ -80,6 +105,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/61/d1/be003d14c880c100d8713b2ca0a286728e6e8b47e50d25e2fab31adc9632/django_js_asset-3.0.1-py3-none-any.whl", hash = "sha256:0b7ee73c45ca65cccbcc2f60cbe8fbc87ff133b543c282cb64fe6c13d7ca4c10", size = 4283 },
]
[[package]]
name = "django-nested-admin"
version = "4.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-monkey-business" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1c/d1/bd500d354dcc3ccbf74507c97dabc5aee18bf0620d2df3deb3971b5c14ed/django-nested-admin-4.1.1.tar.gz", hash = "sha256:645d63b38d579b034a65e0983f1f8cbb8824c75b4232f8d62a1583fa7a9f568f", size = 421628 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fe/e2/2a58c3c21c2e8c383f7e9de2874fa7b443705146e54d0364f1fe6fc31b7e/django_nested_admin-4.1.1-py3-none-any.whl", hash = "sha256:7e72ab7a8ae4c91074f6f709ce38fdf54f9c5f78d19e68772e0f05b83090ec9f", size = 465355 },
]
[[package]]
name = "django-prose-editor"
version = "0.10.3"
@ -239,12 +276,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
]
[[package]]
name = "python-monkey-business"
version = "1.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/21/bc/a6182bb30701d0df25ad336f2dd74343447032e0995025ba82079a94f745/python-monkey-business-1.1.0.tar.gz", hash = "sha256:8393839cc741415ed5ddc2bd58e2d4ce07f966a7d26b7aebff19dcec64818edc", size = 4270 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/43/a2/b6a5cbd5822b4d049adfedf496ce0908480e5a41722fda7b7ffaacb086d6/python_monkey_business-1.1.0-py2.py3-none-any.whl", hash = "sha256:15b4f603c749ba9a7b4f1acd36af023a6c5ba0f7e591c945f8253f0ef44bf389", size = 4670 },
]
[[package]]
name = "servala-fe"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "django" },
{ name = "django-admin-sortable2" },
{ name = "django-jazzmin" },
{ name = "django-nested-admin" },
{ name = "django-prose-editor", extra = ["sanitize"] },
{ name = "django-schema-viewer" },
{ name = "djangorestframework" },
@ -261,7 +310,10 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "django", specifier = ">=5.1.5" },
{ name = "django-admin-sortable2", specifier = ">=2.2.4" },
{ name = "django-browser-reload", marker = "extra == 'dev'", specifier = "~=1.13" },
{ name = "django-jazzmin", specifier = ">=3.0.1" },
{ name = "django-nested-admin", specifier = ">=4.1.1" },
{ name = "django-prose-editor", extras = ["sanitize"], specifier = ">=0.10.3" },
{ name = "django-schema-viewer", specifier = ">=0.5.2" },
{ name = "djangorestframework", specifier = ">=3.15.2" },
@ -269,6 +321,7 @@ requires-dist = [
{ name = "odoorpc", specifier = ">=0.10.1" },
{ name = "pillow", specifier = ">=11.1.0" },
]
provides-extras = ["dev"]
[[package]]
name = "sqlparse"