From 52024a421d92fec6876b631cd8535e9ca0df0a39 Mon Sep 17 00:00:00 2001
From: dcz <dcz@ipipan.waw.pl>
Date: Fri, 27 Oct 2023 15:50:56 +0200
Subject: [PATCH] Free lus module - next phase of development.

---
 .../static/entries/css/unification_frames.css |   4 +
 entries/views.py                              |  13 +-
 freelus/urls.py                               |   3 +
 freelus/views.py                              |  53 +++++-
 .../Unification/LexicalUnitEdit.vue           |   2 +-
 .../unification/free_lu/FreeLuEdit.vue        | 156 +++++++++++++++++-
 6 files changed, 219 insertions(+), 12 deletions(-)

diff --git a/entries/static/entries/css/unification_frames.css b/entries/static/entries/css/unification_frames.css
index 7946523..bfe6d5f 100644
--- a/entries/static/entries/css/unification_frames.css
+++ b/entries/static/entries/css/unification_frames.css
@@ -26,3 +26,7 @@ table.table-button-menu {
 #unified-frame .argument.active {
     background-color: #dee1e4;
 }
+
+#free-lus-frame .argument.active {
+    background-color: #dee1e4;
+}
diff --git a/entries/views.py b/entries/views.py
index 5435fcf..0de4763 100644
--- a/entries/views.py
+++ b/entries/views.py
@@ -9,7 +9,7 @@ import simplejson
 
 from django.contrib.auth.models import User
 from django.contrib.auth.decorators import login_required
-from django.db.models import Prefetch, Q
+from django.db.models import Prefetch, Q, Exists, OuterRef
 from django.http import JsonResponse, QueryDict
 from django.shortcuts import render
 from django.template.context_processors import csrf
@@ -445,7 +445,9 @@ def get_entries(request):
         #entries = entries.filter(subentries__schema_hooks__alternation=2)
 
         if without_frames:
-            entries = entries.filter(lexical_units__frames__isnull=True)
+            entries = entries.filter(Exists(LexicalUnit.objects.filter(base=OuterRef('name'), frames__isnull=True)))
+            # entries = entries.filter(~Exists(LexicalUnit.objects.filter(
+            #     ~Exists(Frame.objects.filter(frames=OuterRef('pk'))))))
 
         total = entries.count()
         if scroller_params['filter']:
@@ -1130,11 +1132,10 @@ def ajax_synsets(request, base, pos):
 
 def lexical_units_without_empty_frames(obj_results):
     for lu in obj_results.all():
-        lu._frames = lu._frames[0] if lu._frames and len(lu._frames) > 0 else None
-        if lu._frames is not None:
-            continue
-        else:
+        if lu._frames and len(lu._frames) > 0:
             yield lu
+        else:
+            continue
 
 
 @ajax(method='get', encode_result=True)
diff --git a/freelus/urls.py b/freelus/urls.py
index 6119d3c..9291677 100644
--- a/freelus/urls.py
+++ b/freelus/urls.py
@@ -6,4 +6,7 @@ app_name = 'freelus'
 
 urlpatterns = [
     path('create_new_slowal_frame/', views.create_new_slowal_frame, name='create_new_slowal_frame'),
+    path('add_argument_to_frame/', views.add_argument_to_frame, name='add_argument_to_frame'),
+    path('change_role/', views.change_role, name='change_role'),
+
 ]
diff --git a/freelus/views.py b/freelus/views.py
index f6832f9..3c929bb 100644
--- a/freelus/views.py
+++ b/freelus/views.py
@@ -5,7 +5,8 @@ from django.http import JsonResponse
 from common.decorators import ajax_required
 from connections.models import Entry, Status
 from meanings.models import LexicalUnit
-from semantics.models import Frame, FrameOpinion
+from semantics.models import Frame, FrameOpinion, Argument, ArgumentRole, SemanticRole, RoleAttribute, RoleSubAttribute, \
+    RoleType
 
 
 @ajax_required
@@ -45,3 +46,53 @@ def create_new_slowal_frame(request):
         return JsonResponse({})
 
     return JsonResponse({})
+
+
+@ajax_required
+@transaction.atomic
+def add_argument_to_frame(request):
+    if request.method == 'POST':
+        frame_id = request.POST['frame_id']
+        frame = Frame.objects.get(id=frame_id)
+
+        argument = Argument(frame=frame)
+        change_role_base(argument, request)
+        argument.save()
+
+        return JsonResponse({})
+
+    return JsonResponse({})
+
+
+@ajax_required
+@transaction.atomic
+def change_role(request):
+    if request.method == 'POST':
+        frame_id = request.POST['frame_id']
+        argument_id = request.POST['argument_id']
+
+        frame_argument = Argument.objects.get(frame_id=frame_id, id=argument_id)
+        change_role_base(frame_argument, request)
+        frame_argument.save()
+    return JsonResponse({})
+
+
+def change_role_base(frame_argument, request):
+    role_id = request.POST['role_id']
+    role_type = request.POST['role_type']
+    attribute_id = request.POST.get('attribute_id', None)
+    sub_attribute_id = request.POST.get('sub_attribute_id', None)
+
+    argument_role = ArgumentRole.objects.filter(role_id=role_id, attribute_id=attribute_id,
+                                                sub_attribute_id=sub_attribute_id).first()
+    if argument_role is None:
+        argument_role = ArgumentRole(role=SemanticRole.objects.get(pk=role_id),
+                                     attribute=None if attribute_id is None else RoleAttribute.objects.get(pk=attribute_id),
+                                     sub_attribute=RoleSubAttribute.objects.get(pk=sub_attribute_id))
+        argument_role.save()
+
+    frame_argument.role = argument_role
+    frame_argument.role_type = RoleType.objects.get(type=role_type)
+
+
+
diff --git a/frontend/src/components/unification/Unification/LexicalUnitEdit.vue b/frontend/src/components/unification/Unification/LexicalUnitEdit.vue
index f841afc..c6a76a3 100644
--- a/frontend/src/components/unification/Unification/LexicalUnitEdit.vue
+++ b/frontend/src/components/unification/Unification/LexicalUnitEdit.vue
@@ -735,7 +735,7 @@ Object.assign(LexicalUnitEdit, {
                 (request, errorType, errorMessage) => {
                   show_error(errorType + ' (' + errorMessage + ')');
                   alert(gettext("Status ramy niew został zmieniony. Błąd: "+errorType + ' (' + errorMessage + ')'));
-                })
+                });
       });
     },
     slowal_frame_ready_rollback(status) {
diff --git a/frontend/src/components/unification/free_lu/FreeLuEdit.vue b/frontend/src/components/unification/free_lu/FreeLuEdit.vue
index 4f552fa..1f94391 100644
--- a/frontend/src/components/unification/free_lu/FreeLuEdit.vue
+++ b/frontend/src/components/unification/free_lu/FreeLuEdit.vue
@@ -8,7 +8,7 @@ import MeaningComponent from "../shared/frame-components/MeaningComponent.vue";
 import SelectionalPreference from "../Unification/SelectionalPreference.js";
 import FreeLuPreview from "./FreeLuPreview.vue";
 import FreeLuElement from "./FreeLuElement.vue";
-import {frames2lexical_units} from "../shared/utils";
+import {frames2lexical_units, send_post_request} from "../shared/utils";
 
 let FreeLuEdit = {
   components: {FreeLuElement, FreeLuPreview}
@@ -55,10 +55,11 @@ Object.assign(FreeLuEdit, {
       hidden_frames: [],
       hierarchy_hyponyms: null,
       lexicalUnitsVisible: true,
+      selected_frame_argument_id: null,
     }
   },
   components: {FreeLuElement, InfoTooltip, Spinner, FreeLuPreview, SlowalFrameComponent, ExamplesComponent, SemanticsSchemataComponent, MeaningComponent},
-  emits: ['goToDisplay', 'refresh', 'swapFrames', 'refreshEntriesList', 'clearUnifiedFrameView'],
+  emits: ['frameSelectionChanged'],
   watch: {
     forceRefresh(newVal, oldVal) {
       this.loadFrame();
@@ -201,7 +202,151 @@ Object.assign(FreeLuEdit, {
               }
           }
           $.prompt(extract_frames_to_new_frame_popup);
-      }
+      },
+      // add_argument() {
+      //     if(this.frame_in_progress) {
+      //         send_post_request('/freelus/add_argument_to_frame/',
+      //             {
+      //                 'frame_id': this.frame_in_progress.id,
+      //             },
+      //             (reponse) => {
+      //                 show_info('Argument został dodany.');
+      //                 alert(gettext("Argument został dodany."));
+      //                 this.loadEntry();
+      //             },
+      //             (request, errorType, errorMessage) => {
+      //                 show_error(errorType + ' (' + errorMessage + ')');
+      //                 alert(gettext("Dodanie argumentu nie powiodło się. Błąd: "+errorType + ' (' + errorMessage + ')'));
+      //             })
+      //     } else {
+      //         alert(gettext("Stwórz nową ramę."));
+      //     }
+      // },
+      change_frame_opinion() {
+          if(this.frame_in_progress) {
+              send_post_request('/freelus/change_frame_opinion/',
+                  {
+                      'frame_id': this.frame_in_progress.id,
+                      'opinion': frame.id,
+                  },
+                  (reponse) => {
+                      show_info('Opinia została zmieniona.');
+                      alert(gettext("Opinia została zmieniona."));
+                      this.loadEntry();
+                  },
+                  (request, errorType, errorMessage) => {
+                      show_error(errorType + ' (' + errorMessage + ')');
+                      alert(gettext("Zmiana opinii nie powiodła się. Błąd: "+errorType + ' (' + errorMessage + ')'));
+                  })
+          } else {
+              alert(gettext("Stwórz nową ramę."));
+          }
+      },
+      roleStrMapping(roleName) {
+          if(roleName === 'role') {
+              return 'required';
+          } else if(roleName === 'modifier') {
+              return 'typical';
+          } else {
+              return roleName;
+          }
+      },
+      change_role(selected_frame_argument_id, api_path) {
+          if (selected_frame_argument_id === null) {
+              alert(gettext("Zaznacz argument, dla którego chcesz wybrać rolę."));
+          } else {
+              const newSelect = function () {
+                  let rolesHTML = roles.map(role => {
+                      return `<label style="background-color:rgb(${role.color})"><input type="radio" name="role" value="${role.id}" /> ${role.role}</label><br />`;
+                  }).join("");
+                  let attributesHTML = role_attributes.map(attribute => {
+                      return `<label><input type="radio" name="attribute" value="${attribute.id}" /> ${attribute.attribute}</label><br />`;
+                  }).join("");
+                  let subAttributesHTML = role_sub_attributes.map(subAttribute => {
+                      return `<label><input type="radio" name="sub_attribute" value="${subAttribute.id}" /> ${subAttribute.sub_attribute}</label><br />`;
+                  }).join("");
+                  // const roleTypeHTML = ['required', 'typical'].map(type => {
+                  const roleTypeHTML = ['role', 'modifier'].map(type => {
+                      return `<label><input type="radio" name="role_type" value="${type}" /> ${this.roleStrMapping(type)}</label><br />`;
+                  }).join("");
+                  return '<div class="row">' +
+                      '<div class="column"><div class="role_select_header">Type</div>' + roleTypeHTML + '</div>' +
+                      '<div class="column"><div class="role_select_header">Role</div>' + rolesHTML + '</div>' +
+                      '<div class="column"><div class="role_select_header">Atrybuty</div>' + attributesHTML + '</div>' +
+                      '<div class="column"><div class="role_select_header">Podatrybuty</div>' + subAttributesHTML + '</div>' +
+                      '</div>';
+              }.bind(this);
+
+              let change_role_popup = {
+                  state0: {
+                      title: 'Dodaj rolÄ™',
+                      html: newSelect(),
+                      buttons: {Anuluj: -1, Zatwierdź: 1},
+                      focus: -1,
+                      submit: function (e, v, m, f) {
+                          if (v == -1) {
+                              $.prompt.close();
+                          }
+                          if (v == 1) {
+                              e.preventDefault();
+
+                              const role_id = normalizeFormData(f.role)[0];
+                              const role_type = normalizeFormData(f.role_type)[0];
+
+                              if (role_id != null && role_type != null) {
+                                  const attribute_id = normalizeFormData(f.attribute)[0];
+
+                                  const sub_attribute_id = normalizeFormData(f.sub_attribute)[0];
+
+                                  const data = {
+                                      'frame_id': this.frame_in_progress.id,
+                                      'argument_id': selected_frame_argument_id,
+                                      'role_type': role_type,
+                                      'role_id': role_id,
+                                      'attribute_id': attribute_id,
+                                      'sub_attribute_id': sub_attribute_id
+                                  };
+                                  $.ajax({
+                                      type: 'post',
+                                      url: '/' + lang + '/freelus/' + api_path + '/',
+                                      dataType: 'json',
+                                      data: data,
+                                      timeout: 60000,
+                                      success: function (response) {
+                                          alert(gettext("Nowa rola zosała zapisana."));
+                                          show_info('Nowa rola zosała zapisana.');
+                                          this.loadEntry();
+                                          $.prompt.close();
+                                      }.bind(this),
+                                      error: function (request, errorType, errorMessage) {
+                                          show_error(errorType + ' (' + errorMessage + ')');
+                                          $.prompt.close();
+                                      }
+                                  });
+                              } else {
+                                  alert(gettext("Musisz wybrać typ oraz rolę."));
+                              }
+                          }
+                      }.bind(this)
+                  }
+              };
+              $.prompt(change_role_popup);
+          }
+      },
+      computeArgumentCSS(argument) {
+          const selectedExampleFrameArguments = this.selectedExamples && this.selectedExamples.length > 0 ? new Set(this.selectedExamples.map(e => e.argument_ids).flat()) : null;
+          return argument.role + ' ' + (argument.id === this.selected_frame_argument_id ? 'active' : argument.hover ? 'bg-highlight' : '')
+              + (selectedExampleFrameArguments != null ? selectedExampleFrameArguments.has(argument.id) ? 'example-yes' : 'example-no' : '');
+      },
+      selectArgument(argument) {
+          if(this.selected_frame_argument_id != argument.id) {
+              this.selected_frame_argument_id = argument.id;
+          } else {
+              this.selected_frame_argument_id = null;
+          }
+          // const selectedArguments = this.frame_in_progress.arguments.filter(argument => argument.selected)
+          // this.$emit('frameSelectionChanged', selectedArguments);
+      },
   },
   mounted() {
     if(this.entryId) {
@@ -236,6 +381,9 @@ export default FreeLuEdit;
         <table class="table-button-menu sticky-top" cellspacing="1">
           <tr style="background-color: white;">
             <td id="create-new-frame" @click="create_new_slowal_frame()" style="padding: 10px 15px 10px 15px; color: #000000;">Nowa rama</td>
+            <td id="add-argument" @click="change_role(-1, 'add_argument_to_frame')" style="padding: 10px 15px 10px 15px; color: #000000;">Dodaj argument</td>
+              <td id="change-role" @click="change_role(selected_frame_argument_id ? selected_frame_argument_id.split('-')[1] : null, 'change_role')" style="padding: 10px 15px 10px 15px; color: #000000;">Zmień rolę</td>
+            <td id="assign-examples" @click="assign_examples()" style="padding: 10px 15px 10px 15px; color: #000000;">Podłącz przykłady</td>
 <!--            <td id="add-arg" @click="create_hyponym_or_hyperonym_relation(true)" style="padding: 10px 15px 10px 15px; color: #000000;">Podrama</td>-->
 <!--            <td style="padding: 10px 15px 10px 15px; color: #000000;" @click="delete_hyponym_or_hyperonym_relation">Usuń powiązanie</td>-->
 <!--            <td style="padding: 10px 15px 10px 15px; color: #000000;" @click="goToEdit">Edytuj</td>-->
@@ -318,7 +466,7 @@ export default FreeLuEdit;
                     </div>
                     <div class="row">
                         <div class="col px-0 frame mb-3 active">
-                            <table class="table m-0 table-borderless border border-secondary text-dark">
+                            <table id="free-lus-frame" class="table m-0 table-borderless border border-secondary text-dark">
                                 <tbody>
                                 <tr class="opinion-row">
                                     <th scope="row" class="py-2 px-1 text-secondary" style="width: 3em;">Opinia</th>
-- 
GitLab