Files
octopus/myproject/products/urls.py
Andrey Smakotin d566819367 Feat: Add inline category creation in catalog with clickable product names
Added inline category creation functionality to catalog page with user-friendly interface:
- Inline input fields for creating root and nested categories
- '+' button in category tree header for root categories
- '+' icon on hover for each category node to create subcategories
- Clickable product/kit names in catalog grid and list views
- AJAX API endpoint for category creation with validation
- User-friendly error messages for duplicate names and constraints
- Clean implementation using clearTimeout pattern to prevent duplicate requests

Technical details:
- New API endpoint: POST /products/api/categories/create/
- Auto-generates slug and SKU for new categories
- Validates uniqueness, parent existence, and circular references
- Single-request submission with proper race condition handling
- Removes debug logging for production-ready code

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 00:24:05 +03:00

98 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.urls import path
from . import views
from .views import api_views
from .views import photo_status_api
app_name = 'products'
urlpatterns = [
# Main unified list for products and kits (default view)
path('', views.CombinedProductListView.as_view(), name='products-list'),
# Каталог с drag-n-drop
path('catalog/', views.CatalogView.as_view(), name='catalog'),
# Legacy URLs for backward compatibility
path('all/', views.CombinedProductListView.as_view(), name='all-products'),
path('products/', views.ProductListView.as_view(), name='product-list-legacy'),
path('kits/', views.ProductKitListView.as_view(), name='productkit-list'),
# CRUD URLs for Product
path('product/create/', views.ProductCreateView.as_view(), name='product-create'),
path('product/<int:pk>/', views.ProductDetailView.as_view(), name='product-detail'),
path('product/<int:pk>/update/', views.ProductUpdateView.as_view(), name='product-update'),
path('product/<int:pk>/delete/', views.ProductDeleteView.as_view(), name='product-delete'),
# Photo management for Product
path('product/photo/<int:pk>/delete/', views.product_photo_delete, name='product-photo-delete'),
path('product/photo/<int:pk>/set-main/', views.product_photo_set_main, name='product-photo-set-main'),
path('product/photo/<int:pk>/move-up/', views.product_photo_move_up, name='product-photo-move-up'),
path('product/photo/<int:pk>/move-down/', views.product_photo_move_down, name='product-photo-move-down'),
path('product/photos/delete-bulk/', views.product_photos_delete_bulk, name='product-photos-delete-bulk'),
# CRUD URLs for ProductKit (комплекты/букеты)
path('kit/create/', views.ProductKitCreateView.as_view(), name='productkit-create'),
path('kit/<int:pk>/', views.ProductKitDetailView.as_view(), name='productkit-detail'),
path('kit/<int:pk>/update/', views.ProductKitUpdateView.as_view(), name='productkit-update'),
path('kit/<int:pk>/delete/', views.ProductKitDeleteView.as_view(), name='productkit-delete'),
path('kit/<int:pk>/make-permanent/', views.ProductKitMakePermanentView.as_view(), name='productkit-make-permanent'),
# Photo management for ProductKit
path('kit/photo/<int:pk>/delete/', views.productkit_photo_delete, name='productkit-photo-delete'),
path('kit/photo/<int:pk>/set-main/', views.productkit_photo_set_main, name='productkit-photo-set-main'),
path('kit/photo/<int:pk>/move-up/', views.productkit_photo_move_up, name='productkit-photo-move-up'),
path('kit/photo/<int:pk>/move-down/', views.productkit_photo_move_down, name='productkit-photo-move-down'),
# API endpoints
path('api/search-products-variants/', views.search_products_and_variants, name='api-search-products-variants'),
path('api/kits/temporary/create/', views.create_temporary_kit_api, name='api-temporary-kit-create'),
path('api/tags/create/', api_views.create_tag_api, name='api-tag-create'),
path('api/tags/<int:pk>/toggle/', api_views.toggle_tag_status_api, name='api-tag-toggle'),
path('api/categories/create/', api_views.create_category_api, name='api-category-create'),
path('api/categories/<int:pk>/rename/', api_views.rename_category_api, name='api-category-rename'),
# Photo processing status API (for AJAX polling)
path('api/photos/status/<str:task_id>/', photo_status_api.photo_processing_status, name='api-photo-status'),
path('api/photos/batch-status/', photo_status_api.batch_photo_status, name='api-batch-photo-status'),
# CRUD URLs for ProductVariantGroup (Варианты товаров)
path('variant-groups/', views.ProductVariantGroupListView.as_view(), name='variantgroup-list'),
path('variant-groups/create/', views.ProductVariantGroupCreateView.as_view(), name='variantgroup-create'),
path('variant-groups/<int:pk>/', views.ProductVariantGroupDetailView.as_view(), name='variantgroup-detail'),
path('variant-groups/<int:pk>/update/', views.ProductVariantGroupUpdateView.as_view(), name='variantgroup-update'),
path('variant-groups/<int:pk>/delete/', views.ProductVariantGroupDeleteView.as_view(), name='variantgroup-delete'),
# AJAX endpoints for ProductVariantGroup item management
path('variant-groups/item/<int:item_id>/move/<str:direction>/', views.product_variant_group_item_move, name='variantgroup-item-move'),
# CRUD URLs for ProductCategory
path('categories/', views.ProductCategoryListView.as_view(), name='category-list'),
path('categories/create/', views.ProductCategoryCreateView.as_view(), name='category-create'),
path('categories/<int:pk>/', views.ProductCategoryDetailView.as_view(), name='category-detail'),
path('categories/<int:pk>/update/', views.ProductCategoryUpdateView.as_view(), name='category-update'),
path('categories/<int:pk>/delete/', views.ProductCategoryDeleteView.as_view(), name='category-delete'),
# Category photo management
path('categories/photo/<int:pk>/delete/', views.category_photo_delete, name='category-photo-delete'),
path('categories/photo/<int:pk>/set-main/', views.category_photo_set_main, name='category-photo-set-main'),
path('categories/photo/<int:pk>/move-up/', views.category_photo_move_up, name='category-photo-move-up'),
path('categories/photo/<int:pk>/move-down/', views.category_photo_move_down, name='category-photo-move-down'),
# CRUD URLs for ProductTag
path('tags/', views.ProductTagListView.as_view(), name='tag-list'),
path('tags/create/', views.ProductTagCreateView.as_view(), name='tag-create'),
path('tags/<int:pk>/', views.ProductTagDetailView.as_view(), name='tag-detail'),
path('tags/<int:pk>/update/', views.ProductTagUpdateView.as_view(), name='tag-update'),
path('tags/<int:pk>/delete/', views.ProductTagDeleteView.as_view(), name='tag-delete'),
# CRUD URLs for ConfigurableKitProduct
path('configurable-kits/', views.ConfigurableKitProductListView.as_view(), name='configurablekit-list'),
path('configurable-kits/create/', views.ConfigurableKitProductCreateView.as_view(), name='configurablekit-create'),
path('configurable-kits/<int:pk>/', views.ConfigurableKitProductDetailView.as_view(), name='configurablekit-detail'),
path('configurable-kits/<int:pk>/update/', views.ConfigurableKitProductUpdateView.as_view(), name='configurablekit-update'),
path('configurable-kits/<int:pk>/delete/', views.ConfigurableKitProductDeleteView.as_view(), name='configurablekit-delete'),
# API для управления вариантами ConfigurableKitProduct
path('configurable-kits/<int:pk>/options/add/', views.add_option_to_configurable, name='configurablekit-add-option'),
path('configurable-kits/<int:pk>/options/<int:option_id>/remove/', views.remove_option_from_configurable, name='configurablekit-remove-option'),
path('configurable-kits/<int:pk>/options/<int:option_id>/set-default/', views.set_option_as_default, name='configurablekit-set-default-option'),
]