diff --git a/backend/core/admin.py b/backend/core/admin.py index 8410dfd..cc2c12e 100644 --- a/backend/core/admin.py +++ b/backend/core/admin.py @@ -59,8 +59,8 @@ class ProductContentAdmin(admin.ModelAdmin): def has_add_permission(self, request): return False - # def has_change_permission(self, request, obj=None): - # return False + def has_change_permission(self, request, obj=None): + return False def has_delete_permission(self, request, obj=None): return False diff --git a/backend/core/views/product_content.py b/backend/core/views/product_content.py index c9f5728..f1c0113 100644 --- a/backend/core/views/product_content.py +++ b/backend/core/views/product_content.py @@ -1,7 +1,8 @@ from core.models import ProductContent from core.serializers import ProductContentSerializer from rest_framework import viewsets - +from rest_framework.response import Response +from rest_framework.decorators import action class ProductContentViewSet(viewsets.ModelViewSet): queryset = ProductContent.objects.all() @@ -12,3 +13,17 @@ class ProductContentViewSet(viewsets.ModelViewSet): "order", ] ordering = ["id"] + + @action(detail=True, methods=['patch']) + def update_alias(self, request, pk=None): + product_content = self.get_object() + alias = request.data.get('alias') + + if alias is not None: + product_content.alias = alias + product_content.save() + + serializer = self.get_serializer(product_content) + return Response(serializer.data) + else: + return Response({'error': 'Alias value is required.'}, status=400) diff --git a/backend/pzserver/urls.py b/backend/pzserver/urls.py index 3859891..6276584 100644 --- a/backend/pzserver/urls.py +++ b/backend/pzserver/urls.py @@ -28,7 +28,6 @@ ) from django.contrib import admin from django.urls import include, path -from pzserver.views import update_aliases from drf_spectacular.views import ( SpectacularAPIView, SpectacularRedocView, @@ -44,6 +43,7 @@ route.register(r"products", ProductViewSet, basename="products") route.register(r"product-contents", ProductContentViewSet, basename="product_contents") route.register(r"product-files", ProductFileViewSet, basename="product_files") +route.register(r"product-contents", ProductContentViewSet, basename="product_contents") from rest_framework.authtoken import views @@ -59,8 +59,6 @@ path("api/logged_user/", LoggedUserView.as_view(), name="logged_user"), path("api/logout/", Logout.as_view(), name="logout"), path("api/shib/", include("core.shibboleth_urls", namespace="shibboleth")), - # API ALIAS - path('api/update-aliases/', update_aliases, name='update_aliases'), # API DOCs path("api/schema/", SpectacularAPIView.as_view(), name="schema"), path( diff --git a/backend/pzserver/views.py b/backend/pzserver/views.py deleted file mode 100644 index f82c506..0000000 --- a/backend/pzserver/views.py +++ /dev/null @@ -1,29 +0,0 @@ -from rest_framework.decorators import api_view, permission_classes -from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response -from core.models import ProductContent -from django.views.decorators.csrf import csrf_exempt - -@api_view(['POST']) -@permission_classes([IsAuthenticated]) -@csrf_exempt -def update_aliases(request): - data = request.data - product_id = data.get('productId') - updates = data.get('updates', []) - - try: - product_contents = ProductContent.objects.filter(product_id=product_id) - for update in updates: - content_id = update.get('id') - alias = update.get('alias') - if content_id and alias: - content = product_contents.get(pk=content_id) - content.alias = alias - content.save() - - return Response({'message': 'Aliases updated successfully.'}) - except ProductContent.DoesNotExist: - return Response({'error': 'Product not found.'}, status=404) - except Exception as e: - return Response({'error': str(e)}, status=500) diff --git a/frontend/components/newProduct/Step3.js b/frontend/components/newProduct/Step3.js index 623bcd2..933b02b 100644 --- a/frontend/components/newProduct/Step3.js +++ b/frontend/components/newProduct/Step3.js @@ -59,17 +59,24 @@ export default function NewProductStep3({ productId, onNext, onPrev }) { const loadContents = React.useCallback(async () => { setLoading(true) - getProductContents(productId) - .then(res => { - setProductColumns(res.results) - setLoading(false) - }) - .catch(res => { - setLoading(false) - if (res.response.status === 500) { - catchFormError(res.response.data) + try { + const response = await getProductContents(productId) + setProductColumns(response.results) + + const aliases = {} + response.results.forEach(row => { + if (row.alias) { + aliases[row.column_name] = row.alias } }) + setEditableFields(aliases) + setLoading(false) + } catch (error) { + setLoading(false) + if (error.response && error.response.status === 500) { + catchFormError(error.response.data) + } + } }, [productId]) useEffect(() => { @@ -114,29 +121,18 @@ export default function NewProductStep3({ productId, onNext, onPrev }) { event.preventDefault() } - const handleEditField = (pc, value) => { + const handleAlias = (pc, value) => { setEditableFields(prevState => ({ ...prevState, [pc.column_name]: value })) - updateAliasOnServer(pc.id, value) - } - const updateAliasOnServer = async (contentId, aliasValue) => { - try { - await axios.post('/api/update-aliases/', { - productId: productId, - updates: [ - { - id: contentId, - alias: aliasValue - } - ] - }); - } catch (error) { - console.error('Error updating alias:', error); - } - }; + axios.patch(`/api/product-contents/${pc.id}/`, { alias: value }) + .then(response => { + }) + .catch(error => { + }) + } const handleCancelEdit = pc => { const updatedEditableFields = { ...editableFields } @@ -157,7 +153,7 @@ export default function NewProductStep3({ productId, onNext, onPrev }) { } }) - const isOptionSelected = pc.ucd !== null; + const isOptionSelected = pc.ucd !== null return ( @@ -181,7 +177,18 @@ export default function NewProductStep3({ productId, onNext, onPrev }) { handleEditField(pc, e.target.value)} + onChange={e => handleAlias(pc, e.target.value)} + onBlur={() => { + // console.log(`${pc.column_name}: ${editableFields[pc.column_name]}`) + handleAlias(pc, editableFields[pc.column_name]) + }} + onKeyPress={event => { + if (event.key === 'Enter' || event.key === 'Tab') { + handleAlias(pc, editableFields[pc.column_name]) + // console.log(`${pc.column_name}: ${editableFields[pc.column_name]}`) + editFieldRefs.current[pc.column_name].blur() + } + }} InputProps={{ endAdornment: ( @@ -192,7 +199,7 @@ export default function NewProductStep3({ productId, onNext, onPrev }) { ) }} inputRef={ref => { - editFieldRefs.current[pc.column_name] = ref; + editFieldRefs.current[pc.column_name] = ref }} autoFocus /> @@ -214,7 +221,7 @@ export default function NewProductStep3({ productId, onNext, onPrev }) { ))} handleEditField(pc, '')} + onClick={() => handleAlias(pc, '')} onMouseDown={handleMouseDownPassword} >