From 1f239a0fabbeb6b9480b25095bce9d5d79c0def5 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Thu, 10 Oct 2024 10:34:43 +0100 Subject: [PATCH 01/94] prototyping on flagging feature --- portality/forms/application_forms.py | 102 +++++++++++++++++- portality/static/js/application_form.js | 6 +- portality/static/js/formulaic.js | 20 ++++ .../includes/_editorial_side_panel.html | 9 ++ 4 files changed, 135 insertions(+), 2 deletions(-) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index 8d4adcd85d..be523849e6 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -2,6 +2,7 @@ ~~ApplicationForm:Feature~~ """ from copy import deepcopy +from dataclasses import Field from wtforms import StringField, TextAreaField, IntegerField, BooleanField, SelectMultipleField, \ SelectField, \ @@ -2025,6 +2026,88 @@ class FieldDefinitions: "input": "hidden" } + FLAG = { + "name": "flag", + "input": "group", + "label": "Flag", + "subfields": [ + "flag_setter", + "flag_created_date", + "flag_deadline", + "flag_note", + "flag_note_id", + "flag_setter_id", + "flag_assignee" + ], + "template": templates.AF_FIELD, + "entry_template": templates.AF_ENTRY_GOUP, + "widgets": [ + "flag_manager" + # { + # "show_on_click": {"button_value": "Flag this record"}, + # "note_modal" + # } + ] + } + + # ~~->$ NoteAuthor:FormField~~ + FLAG_SETTER = { + "subfield": True, + "name": "flag_setter", + "group": "flag", + "input": "text", + "disabled": True + } + + # ~~->$ NoteDate:FormField~~ + FLAG_CREATED_DATE = { + "subfield": True, + "name": "flag_created_date", + "group": "flag", + "input": "text", + "disabled": True + } + + FLAG_DEADLINE = { + "subfield": True, + "name": "flag_deadline", + "group": "flag", + "input": "text", + "disabled": True + } + + FLAG_NOTE = { + "subfield": True, + "name": "flag_note", + "group": "flag", + "input": "textarea", + "disabled": False # "disable_except_assignee_owner_admin", + } + + # ~~->$ NoteID:FormField~~ + FLAG_NOTE_ID = { + "subfield": True, + "name": "flag_note_id", + "group": "flag", + "input": "hidden" + } + + # ~~->$ NoteAuthorID:FormField~~ + FLAG_SETTER_ID = { + "subfield": True, + "name": "flag_setter_id", + "group": "flag", + "input": "hidden" + } + + FLAG_ASSIGNEE = { + "subfield": True, + "name": "flag_assignee", + "group": "flag", + "input": "text", + "disabled": False # "disable_except_assignee_owner_admin" + } + # ~~->$ OptionalValidation:FormField~~ OPTIONAL_VALIDATION = { "name": "make_all_fields_optional", @@ -2302,6 +2385,21 @@ class FieldSetDefinitions: ] } + FLAG = { + "name": "flag", + "label": "Flag", + "fields": [ + FieldDefinitions.FLAG["name"], + FieldDefinitions.FLAG_SETTER["name"], + FieldDefinitions.FLAG_CREATED_DATE["name"], + FieldDefinitions.FLAG_DEADLINE["name"], + FieldDefinitions.FLAG_NOTE["name"], + FieldDefinitions.FLAG_NOTE_ID["name"], + FieldDefinitions.FLAG_SETTER_ID["name"], + FieldDefinitions.FLAG_ASSIGNEE["name"], + ] + } + # ~~->$ Notes:FieldSet~~ NOTES = { "name": "notes", @@ -2434,6 +2532,7 @@ class ApplicationContextDefinitions: FieldSetDefinitions.REVIEWERS["name"], FieldSetDefinitions.CONTINUATIONS["name"], FieldSetDefinitions.SUBJECT["name"], + FieldSetDefinitions.FLAG["name"], FieldSetDefinitions.NOTES["name"] ] MANED["processor"] = application_processors.AdminApplication @@ -3174,7 +3273,8 @@ def wtforms(field, settings): "trim_whitespace": "formulaic.widgets.newTrimWhitespace", # ~~-> TrimWhitespace:FormWidget~~ "note_modal": "formulaic.widgets.newNoteModal", # ~~-> NoteModal:FormWidget~~, "autocheck": "formulaic.widgets.newAutocheck", # ~~-> Autocheck:FormWidget~~ - "issn_link": "formulaic.widgets.newIssnLink" # ~~-> IssnLink:FormWidget~~, + "issn_link": "formulaic.widgets.newIssnLink", # ~~-> IssnLink:FormWidget~~, + "flag_manager": "formulaic.widgets.newFlagManager" # ~~-> FlagManager:FormWidget~~ } diff --git a/portality/static/js/application_form.js b/portality/static/js/application_form.js index e7959a2db3..9dbdf6f609 100644 --- a/portality/static/js/application_form.js +++ b/portality/static/js/application_form.js @@ -506,7 +506,11 @@ doaj.af.EditorialApplicationForm = class extends doaj.af.BaseApplicationForm { beforeUnload(event) { if (!this.changed || this.submitting) { - event.cancel(); + try { + event.cancel(); + } catch(e) { + // do nothing + } } return "Any unsaved changes may be lost" } diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index 0c5932c3ce..d49df6b8cf 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1109,6 +1109,26 @@ var formulaic = { return elements.find(containerSelector); }, + newFlagManager : function(params) { + return edges.instantiate(formulaic.widgets.FlagManager, params); + }, + FlagManager: function(params) { + this.fieldDef = params.fieldDef; + this.form = params.formulaic; + + this.namespace = "formulaic-flagmanager-" + this.fieldDef.name; + + this.init = function() { + this.container = $("." + this.fieldDef.name + "__container"); + this.container.hide(); + + let cont = formulaic.widgets._make_empty_container(this.namespace, "flagmanager", this.form, this.fieldDef); + cont.html("Hidden flag stuff") + } + + this.init(); + }, + newAutocheck : function(params) { return edges.instantiate(formulaic.widgets.Autocheck, params); }, diff --git a/portality/templates-v2/management/_application-form/includes/_editorial_side_panel.html b/portality/templates-v2/management/_application-form/includes/_editorial_side_panel.html index f7047bd426..737a971ad0 100644 --- a/portality/templates-v2/management/_application-form/includes/_editorial_side_panel.html +++ b/portality/templates-v2/management/_application-form/includes/_editorial_side_panel.html @@ -47,6 +47,15 @@

Locked for editing until +
+ {% set fs = formulaic_context.fieldset("flag") %} + {% if fs %} + {% for f in fs.fields() %} + {% set field_template = f.template %} + {% include field_template %} + {% endfor %} + {% endif %} +
{% set fs = formulaic_context.fieldset("notes") %} {% if fs %} From 98c66ddfe88d3ae33e37485358ad9ce6becd6247 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Thu, 17 Oct 2024 12:19:15 +0100 Subject: [PATCH 02/94] some prototyping around converting notes to flags --- portality/forms/application_forms.py | 10 ++-- portality/static/js/formulaic.js | 86 +++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 8 deletions(-) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index be523849e6..b356eb2ab5 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -1978,7 +1978,8 @@ class FieldDefinitions: "entry_template": templates.AF_ENTRY_GOUP, "widgets": [ {"infinite_repeat": {"enable_on_repeat": ["textarea"]}}, - "note_modal" + "note_modal", + "convert_to_flag" ], "merge_disabled": "merge_disabled_notes", } @@ -2043,10 +2044,6 @@ class FieldDefinitions: "entry_template": templates.AF_ENTRY_GOUP, "widgets": [ "flag_manager" - # { - # "show_on_click": {"button_value": "Flag this record"}, - # "note_modal" - # } ] } @@ -3274,7 +3271,8 @@ def wtforms(field, settings): "note_modal": "formulaic.widgets.newNoteModal", # ~~-> NoteModal:FormWidget~~, "autocheck": "formulaic.widgets.newAutocheck", # ~~-> Autocheck:FormWidget~~ "issn_link": "formulaic.widgets.newIssnLink", # ~~-> IssnLink:FormWidget~~, - "flag_manager": "formulaic.widgets.newFlagManager" # ~~-> FlagManager:FormWidget~~ + "flag_manager": "formulaic.widgets.newFlagManager", # ~~-> FlagManager:FormWidget~~ + "convert_to_flag": "formulaic.widgets.newConvertToFlag" # ~~-> ConvertToFlag:FormWidget~~ } diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index d49df6b8cf..0f11b41fd9 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1122,8 +1122,90 @@ var formulaic = { this.container = $("." + this.fieldDef.name + "__container"); this.container.hide(); - let cont = formulaic.widgets._make_empty_container(this.namespace, "flagmanager", this.form, this.fieldDef); - cont.html("Hidden flag stuff") + let cont = formulaic.widgets._make_empty_container(this.namespace, "autochecks", this.form, this.fieldDef); + let clearFlagClass = edges.css_classes(this.namespace, "clear-flag"); + let resolveFlagClass = edges.css_classes(this.namespace, "resolve-flag"); + let controls = ``; + cont.html(controls); + + + let addFlagContainer = edges.css_classes(this.namespace, "add-flag-container"); + let addFlagClass = edges.css_classes(this.namespace, "add-flag"); + let frag = `
`; + this.container.after(frag); + + let addFlagClassSelector = edges.css_class_selector(this.namespace, "add-flag"); + edges.on(addFlagClassSelector, "click", this, "addFlag"); + + let clearFlagClassSelector = edges.css_class_selector(this.namespace, "clear-flag"); + edges.on(clearFlagClassSelector, "click", this, "clearFlag"); + + let resolveFlagClassSelector = edges.css_class_selector(this.namespace, "resolve-flag"); + edges.on(resolveFlagClassSelector, "click", this, "resolveFlag"); + } + + this.addFlag = function() { + let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); + $(addFlagContainer).hide(); + this.container.show(); + } + + this.clearFlag = function() { + // TODO: actually clear the flag content from the form + this.container.hide(); + let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); + $(addFlagContainer).show(); + } + + this.resolveFlag = function() { + let flagNote = this.container.find("#flag-flag_note"); + + let noteWidgets = formulaic.active.activeWidgets["notes"]; + // TODO: we'll need a way to actually find the InfiniteRepeat widget for certain + let irw = noteWidgets[0]; + irw.addField(); + + let justAdded = irw.container.find("div").first(); + let textarea = justAdded.find("textarea"); + textarea.val("Flag resolved: " + flagNote.val()); + + this.clearFlag(); + } + + this.init(); + }, + + newConvertToFlag : function(params) { + return edges.instantiate(formulaic.widgets.ConvertToFlag, params); + }, + ConvertToFlag: function(params) { + this.fieldDef = params.fieldDef; + this.form = params.formulaic; + + this.namespace = "formulaic-convertoflag-" + this.fieldDef.name; + + this.init = function () { + var flagClass = edges.css_classes(this.ns, "flag"); + let group = $("div[name='" + this.fieldDef["name"] + "__group']") + var textarea = group.find("textarea"); + + for (var i = 0; i < textarea.length; i++) { + var container = $(textarea[i]); + $(``).insertAfter(container); + } + + var flagSelector = edges.css_class_selector(this.ns, "flag"); + edges.on(flagSelector, "click", this, "convertToFlag"); + } + + this.convertToFlag = function(element) { + // TODO: only do this if a flag is not already set, otherwise say flag must be cleared or resolved first + var textarea = $(element).prev(); + var flagNote = textarea.val(); + var flagWidgets = formulaic.active.activeWidgets["flag"]; + var flagWidget = flagWidgets[0]; + flagWidget.addFlag(); + flagWidget.container.find("#flag-flag_note").val(flagNote); } this.init(); From 80cdba36722b66c67a035b20295e5270d20ed42b Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Thu, 17 Oct 2024 13:41:45 +0100 Subject: [PATCH 03/94] remove erroneous import --- portality/forms/application_forms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index b356eb2ab5..e190750895 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -2,7 +2,6 @@ ~~ApplicationForm:Feature~~ """ from copy import deepcopy -from dataclasses import Field from wtforms import StringField, TextAreaField, IntegerField, BooleanField, SelectMultipleField, \ SelectField, \ From a598eb9eb3b801a5a3bc1527186a744d0eaf350a Mon Sep 17 00:00:00 2001 From: amdomanska Date: Wed, 23 Oct 2024 18:58:54 +0100 Subject: [PATCH 04/94] remove convert_to_flag converter --- portality/forms/application_forms.py | 3 +-- portality/static/js/formulaic.js | 36 ---------------------------- 2 files changed, 1 insertion(+), 38 deletions(-) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index e190750895..89496565af 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -1977,8 +1977,7 @@ class FieldDefinitions: "entry_template": templates.AF_ENTRY_GOUP, "widgets": [ {"infinite_repeat": {"enable_on_repeat": ["textarea"]}}, - "note_modal", - "convert_to_flag" + "note_modal" ], "merge_disabled": "merge_disabled_notes", } diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index 0f11b41fd9..95caadde44 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1175,42 +1175,6 @@ var formulaic = { this.init(); }, - newConvertToFlag : function(params) { - return edges.instantiate(formulaic.widgets.ConvertToFlag, params); - }, - ConvertToFlag: function(params) { - this.fieldDef = params.fieldDef; - this.form = params.formulaic; - - this.namespace = "formulaic-convertoflag-" + this.fieldDef.name; - - this.init = function () { - var flagClass = edges.css_classes(this.ns, "flag"); - let group = $("div[name='" + this.fieldDef["name"] + "__group']") - var textarea = group.find("textarea"); - - for (var i = 0; i < textarea.length; i++) { - var container = $(textarea[i]); - $(``).insertAfter(container); - } - - var flagSelector = edges.css_class_selector(this.ns, "flag"); - edges.on(flagSelector, "click", this, "convertToFlag"); - } - - this.convertToFlag = function(element) { - // TODO: only do this if a flag is not already set, otherwise say flag must be cleared or resolved first - var textarea = $(element).prev(); - var flagNote = textarea.val(); - var flagWidgets = formulaic.active.activeWidgets["flag"]; - var flagWidget = flagWidgets[0]; - flagWidget.addFlag(); - flagWidget.container.find("#flag-flag_note").val(flagNote); - } - - this.init(); - }, - newAutocheck : function(params) { return edges.instantiate(formulaic.widgets.Autocheck, params); }, From 33d0d697d93b2836634ff9ce21d18544703eb0d4 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Wed, 23 Oct 2024 19:00:49 +0100 Subject: [PATCH 05/94] remove convert to flag continued --- portality/forms/application_forms.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index 89496565af..fa5eb665aa 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -3269,8 +3269,7 @@ def wtforms(field, settings): "note_modal": "formulaic.widgets.newNoteModal", # ~~-> NoteModal:FormWidget~~, "autocheck": "formulaic.widgets.newAutocheck", # ~~-> Autocheck:FormWidget~~ "issn_link": "formulaic.widgets.newIssnLink", # ~~-> IssnLink:FormWidget~~, - "flag_manager": "formulaic.widgets.newFlagManager", # ~~-> FlagManager:FormWidget~~ - "convert_to_flag": "formulaic.widgets.newConvertToFlag" # ~~-> ConvertToFlag:FormWidget~~ + "flag_manager": "formulaic.widgets.newFlagManager" # ~~-> FlagManager:FormWidget~~ } From f57f7284351eeea2b5f1ff77c6d8590ee5c0ccb2 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Wed, 23 Oct 2024 19:38:38 +0100 Subject: [PATCH 06/94] add flag structs to the notes --- portality/models/v2/shared_structs.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/portality/models/v2/shared_structs.py b/portality/models/v2/shared_structs.py index 6c2c031af1..5996792528 100644 --- a/portality/models/v2/shared_structs.py +++ b/portality/models/v2/shared_structs.py @@ -208,6 +208,17 @@ "note" : {"coerce" : "unicode"}, "date" : {"coerce" : "utcdatetime"}, "author_id" : {"coerce" : "unicode"}, # account_id of the note's author + }, + "objects": [ + "flag" + ], + "structs": { + "flag": { + "fields": { + "assigned_to": {"coerce" : "unicode"}, # account_id of the note's assignee + "deadline": {"coerce" : "utcdatetime"} + } + } } }, } @@ -217,6 +228,7 @@ "country" : {"coerce" : "unicode"}, "has_apc" : {"coerce" : "unicode"}, "has_seal" : {"coerce" : "unicode"}, + "has_flag" : {"coerce" : "unicode"}, "unpunctitle" : {"coerce" : "unicode"}, "asciiunpunctitle" : {"coerce" : "unicode"}, "continued" : {"coerce" : "unicode"}, From 5bd175eeadf5bf41fea734376d56d5a9ceb58ac1 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Tue, 29 Oct 2024 18:56:03 +0000 Subject: [PATCH 07/94] add flag to the model and save from the form as a flag --- portality/crosswalks/journal_form.py | 11 +++++++ portality/forms/application_forms.py | 3 -- portality/models/v2/journal.py | 4 +-- portality/static/js/formulaic.js | 44 ++++++++++++++-------------- 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/portality/crosswalks/journal_form.py b/portality/crosswalks/journal_form.py index ecdc20c61a..0d89b6c77e 100644 --- a/portality/crosswalks/journal_form.py +++ b/portality/crosswalks/journal_form.py @@ -270,6 +270,17 @@ def form2admin(cls, form, obj): obj.add_note(formnote["note"], date=note_date, id=note_id, author_id=formnote["note_author_id"]) + if getattr(form, "flag", None): + flag = form.flag.data + flag_date = flag["flag_created_date"] + flag_deadline = flag["flag_deadline"] + flag_assigned_to = flag["flag_assignee"] + flag_author = flag["flag_setter"] + flag_id = flag["flag_note_id"] + flag_note = flag["flag_note"] + obj.add_note(flag_note, date=flag_date, id=flag_id, + author_id=flag_author, assigned_to=flag_assigned_to, deadline=flag_deadline) + if getattr(form, 'owner', None): owner = form.owner.data if owner: diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index fa5eb665aa..77f111c200 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -2051,7 +2051,6 @@ class FieldDefinitions: "name": "flag_setter", "group": "flag", "input": "text", - "disabled": True } # ~~->$ NoteDate:FormField~~ @@ -2060,7 +2059,6 @@ class FieldDefinitions: "name": "flag_created_date", "group": "flag", "input": "text", - "disabled": True } FLAG_DEADLINE = { @@ -2068,7 +2066,6 @@ class FieldDefinitions: "name": "flag_deadline", "group": "flag", "input": "text", - "disabled": True } FLAG_NOTE = { diff --git a/portality/models/v2/journal.py b/portality/models/v2/journal.py index f97f8084f2..c9526c588f 100644 --- a/portality/models/v2/journal.py +++ b/portality/models/v2/journal.py @@ -272,10 +272,10 @@ def set_contact(self, name, email): def remove_contact(self): self.__seamless__.delete("admin.contact") - def add_note(self, note, date=None, id=None, author_id=None): + def add_note(self, note, date=None, id=None, author_id=None, assigned_to=None, deadline=None): if not date: date = dates.now_str() - obj = {"date": date, "note": note, "id": id, "author_id": author_id} + obj = {"date": date, "note": note, "id": id, "author_id": author_id, "flag": {"assigned_to": assigned_to, "deadline": deadline}} self.__seamless__.delete_from_list("admin.notes", matchsub=obj) if not id: obj["id"] = uuid.uuid4() diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index 95caadde44..f818494029 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1120,7 +1120,7 @@ var formulaic = { this.init = function() { this.container = $("." + this.fieldDef.name + "__container"); - this.container.hide(); + // this.container.hide(); let cont = formulaic.widgets._make_empty_container(this.namespace, "autochecks", this.form, this.fieldDef); let clearFlagClass = edges.css_classes(this.namespace, "clear-flag"); @@ -1140,36 +1140,36 @@ var formulaic = { let clearFlagClassSelector = edges.css_class_selector(this.namespace, "clear-flag"); edges.on(clearFlagClassSelector, "click", this, "clearFlag"); - let resolveFlagClassSelector = edges.css_class_selector(this.namespace, "resolve-flag"); - edges.on(resolveFlagClassSelector, "click", this, "resolveFlag"); + // let resolveFlagClassSelector = edges.css_class_selector(this.namespace, "resolve-flag"); + // edges.on(resolveFlagClassSelector, "click", this, "resolveFlag"); } this.addFlag = function() { - let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); - $(addFlagContainer).hide(); - this.container.show(); + // let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); + // $(addFlagContainer).hide(); + // this.container.show(); } this.clearFlag = function() { - // TODO: actually clear the flag content from the form - this.container.hide(); - let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); - $(addFlagContainer).show(); + $(this.container).find('input').val(''); + // this.container.hide(); + // let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); + // $(addFlagContainer).show(); } this.resolveFlag = function() { - let flagNote = this.container.find("#flag-flag_note"); - - let noteWidgets = formulaic.active.activeWidgets["notes"]; - // TODO: we'll need a way to actually find the InfiniteRepeat widget for certain - let irw = noteWidgets[0]; - irw.addField(); - - let justAdded = irw.container.find("div").first(); - let textarea = justAdded.find("textarea"); - textarea.val("Flag resolved: " + flagNote.val()); - - this.clearFlag(); + // let flagNote = this.container.find("#flag-flag_note"); + // + // let noteWidgets = formulaic.active.activeWidgets["notes"]; + // // TODO: we'll need a way to actually find the InfiniteRepeat widget for certain + // let irw = noteWidgets[0]; + // irw.addField(); + // + // let justAdded = irw.container.find("div").first(); + // let textarea = justAdded.find("textarea"); + // textarea.val("Flag resolved: " + flagNote.val()); + // + // this.clearFlag(); } this.init(); From ed6c0b8a022e2334c8194b1837c64ee9a991a52f Mon Sep 17 00:00:00 2001 From: amdomanska Date: Tue, 29 Oct 2024 19:02:12 +0000 Subject: [PATCH 08/94] add 'clear flag' functionality --- portality/static/js/formulaic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index f818494029..63daf62084 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1151,7 +1151,7 @@ var formulaic = { } this.clearFlag = function() { - $(this.container).find('input').val(''); + $(this.container).find('input,textarea').val(''); // this.container.hide(); // let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); // $(addFlagContainer).show(); From 7070a83e437c7185fbeb1c33404b7c6611942623 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Tue, 29 Oct 2024 19:31:40 +0000 Subject: [PATCH 09/94] add 'has_flag' to index --- portality/models/v2/journal.py | 5 +++++ portality/static/js/formulaic.js | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/portality/models/v2/journal.py b/portality/models/v2/journal.py index c9526c588f..d0bc5f6700 100644 --- a/portality/models/v2/journal.py +++ b/portality/models/v2/journal.py @@ -379,6 +379,7 @@ def _generate_index(self): continued = "No" has_editor_group = "No" has_editor = "No" + has_flag = False # the places we're going to get those fields from cbib = self.bibjson() @@ -421,6 +422,9 @@ def _generate_index(self): for l in cbib.licences: license.append(l.get("type")) + # check for any flags + has_flag = any("assigned_to" in note.get("flag", {}) and note["flag"]["assigned_to"] is not None for note in self.notes) + # deduplicate the lists titles = list(set(titles)) subjects = list(set(subjects)) @@ -466,6 +470,7 @@ def _generate_index(self): index["unpunctitle"] = unpunctitle if asciiunpunctitle is not None: index["asciiunpunctitle"] = asciiunpunctitle + index["has_flag"] = has_flag index["continued"] = continued index["has_editor_group"] = has_editor_group index["has_editor"] = has_editor diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index 63daf62084..a6dbfd315b 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1120,7 +1120,7 @@ var formulaic = { this.init = function() { this.container = $("." + this.fieldDef.name + "__container"); - // this.container.hide(); + this.container.hide(); let cont = formulaic.widgets._make_empty_container(this.namespace, "autochecks", this.form, this.fieldDef); let clearFlagClass = edges.css_classes(this.namespace, "clear-flag"); @@ -1145,9 +1145,9 @@ var formulaic = { } this.addFlag = function() { - // let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); - // $(addFlagContainer).hide(); - // this.container.show(); + let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); + $(addFlagContainer).hide(); + this.container.show(); } this.clearFlag = function() { From e58fb2a4d13d79b8770dbfff822febbc819c3248 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Tue, 29 Oct 2024 19:49:24 +0000 Subject: [PATCH 10/94] add 'notes_except_flags' and 'flags' to journal model properties; allow order_notes to order without flags --- portality/models/v2/journal.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/portality/models/v2/journal.py b/portality/models/v2/journal.py index d0bc5f6700..a909c8b2e1 100644 --- a/portality/models/v2/journal.py +++ b/portality/models/v2/journal.py @@ -299,9 +299,17 @@ def notes(self): return self.__seamless__.get_list("admin.notes") @property - def ordered_notes(self): + def notes_except_flags(self): + return [note for note in self.notes if not note.get("flag") or not note["flag"].get("assigned_to")] + + @property + def flags(self): + return [note for note in self.notes if note.get("flag") and note["flag"].get("assigned_to")] + + @property + def ordered_notes(self, with_flags=True): """Orders notes by newest first""" - notes = self.notes + notes = self.notes if with_flags else self.notes_except_flags clusters = {} for note in notes: if "date" not in note: From 2e600fb3373e0bb1e5206ba1e656c2dc70794c16 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Wed, 30 Oct 2024 18:40:19 +0000 Subject: [PATCH 11/94] display existing flag correctly in the form --- portality/crosswalks/journal_form.py | 10 ++++++- portality/models/v2/journal.py | 44 +++++++++++++++++----------- portality/static/js/formulaic.js | 12 ++++---- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/portality/crosswalks/journal_form.py b/portality/crosswalks/journal_form.py index 0d89b6c77e..e3571a48d5 100644 --- a/portality/crosswalks/journal_form.py +++ b/portality/crosswalks/journal_form.py @@ -453,7 +453,7 @@ def bibjson2form(cls, bibjson, forminfo): @classmethod def admin2form(cls, obj, forminfo): forminfo['notes'] = [] - for n in obj.ordered_notes: + for n in obj.ordered_notes_except_flags: author_id = n.get('author_id', '') note_author_name = f'{Account.get_name_safe(author_id)} ({author_id})' if author_id else '' note_obj = {'note': n['note'], 'note_date': n['date'], 'note_id': n['id'], @@ -462,6 +462,14 @@ def admin2form(cls, obj, forminfo): } forminfo['notes'].append(note_obj) + if obj.flags: + # display only the newest flag + flag = obj.flags[0] + flag_obj = {"flag_created_date": flag["date"], "flag_note": flag["note"], "flag_note_id": flag["id"], + "flag_setter": flag["author_id"], "flag_assignee": flag["flag"]["assigned_to"], + "flag_deadline": flag["flag"]["deadline"]} + forminfo['flag'] = flag_obj + forminfo['owner'] = obj.owner if obj.editor_group is not None: forminfo['editor_group'] = obj.editor_group diff --git a/portality/models/v2/journal.py b/portality/models/v2/journal.py index a909c8b2e1..0322cd525c 100644 --- a/portality/models/v2/journal.py +++ b/portality/models/v2/journal.py @@ -62,6 +62,25 @@ class ContinuationException(Exception): pass +def _order_notes(notes): + clusters = {} + for note in notes: + if "date" not in note: + note[ + "date"] = DEFAULT_TIMESTAMP_VAL # this really means something is broken with note date setting, which needs to be fixed + if note["date"] not in clusters: + clusters[note["date"]] = [note] + else: + clusters[note["date"]].append(note) + + ordered_keys = sorted(list(clusters.keys()), reverse=True) + ordered = [] + for key in ordered_keys: + clusters[key].reverse() + ordered += clusters[key] + return ordered + + class JournalLikeObject(SeamlessMixin, DomainObject): @classmethod @@ -307,24 +326,15 @@ def flags(self): return [note for note in self.notes if note.get("flag") and note["flag"].get("assigned_to")] @property - def ordered_notes(self, with_flags=True): + def ordered_notes(self): """Orders notes by newest first""" - notes = self.notes if with_flags else self.notes_except_flags - clusters = {} - for note in notes: - if "date" not in note: - note["date"] = DEFAULT_TIMESTAMP_VAL # this really means something is broken with note date setting, which needs to be fixed - if note["date"] not in clusters: - clusters[note["date"]] = [note] - else: - clusters[note["date"]].append(note) - - ordered_keys = sorted(list(clusters.keys()), reverse=True) - ordered = [] - for key in ordered_keys: - clusters[key].reverse() - ordered += clusters[key] - return ordered + notes = self.notes + return _order_notes(notes) + + @property + def ordered_notes_except_flags(self): + notes = self.notes_except_flags + return _order_notes(notes) def bibjson(self): bj = self.__seamless__.get_single("bibjson") diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index a6dbfd315b..8b03588ab4 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1120,8 +1120,10 @@ var formulaic = { this.init = function() { this.container = $("." + this.fieldDef.name + "__container"); - this.container.hide(); - + let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); + $(addFlagContainer).hide(); + // this.container.hide(); + // let cont = formulaic.widgets._make_empty_container(this.namespace, "autochecks", this.form, this.fieldDef); let clearFlagClass = edges.css_classes(this.namespace, "clear-flag"); let resolveFlagClass = edges.css_classes(this.namespace, "resolve-flag"); @@ -1145,9 +1147,9 @@ var formulaic = { } this.addFlag = function() { - let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); - $(addFlagContainer).hide(); - this.container.show(); + // let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); + // $(addFlagContainer).hide(); + // this.container.show(); } this.clearFlag = function() { From 1097dad7389f8aa12565f5a91f7d70036195fca9 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Thu, 31 Oct 2024 13:53:13 +0000 Subject: [PATCH 12/94] make flags field repeatable with max 2 values - one for current, one for new; display it correctly --- cms/sass/components/_removable-fields.scss | 2 +- portality/crosswalks/journal_form.py | 12 ++-- portality/forms/application_forms.py | 30 ++++++--- portality/static/js/formulaic.js | 17 +++-- .../includes/_flag_entry.html | 6 ++ .../includes/_flags_list.html | 64 +++++++++++++++++++ portality/ui/templates.py | 2 + 7 files changed, 111 insertions(+), 22 deletions(-) create mode 100644 portality/templates-v2/_application-form/includes/_flag_entry.html create mode 100644 portality/templates-v2/_application-form/includes/_flags_list.html diff --git a/cms/sass/components/_removable-fields.scss b/cms/sass/components/_removable-fields.scss index 9508ae47bf..9b80386b24 100644 --- a/cms/sass/components/_removable-fields.scss +++ b/cms/sass/components/_removable-fields.scss @@ -7,7 +7,7 @@ @include unstyled-list; } - label { + label.hiddenLabel { @extend .sr-only; // a11y-friendly, can’t add class to the form itself } } diff --git a/portality/crosswalks/journal_form.py b/portality/crosswalks/journal_form.py index e3571a48d5..a1ffdac870 100644 --- a/portality/crosswalks/journal_form.py +++ b/portality/crosswalks/journal_form.py @@ -270,8 +270,9 @@ def form2admin(cls, form, obj): obj.add_note(formnote["note"], date=note_date, id=note_id, author_id=formnote["note_author_id"]) - if getattr(form, "flag", None): - flag = form.flag.data + if getattr(form, "flags", None): + print(form.flags.data) + flag = form.flags.data[0] flag_date = flag["flag_created_date"] flag_deadline = flag["flag_deadline"] flag_assigned_to = flag["flag_assignee"] @@ -452,6 +453,7 @@ def bibjson2form(cls, bibjson, forminfo): @classmethod def admin2form(cls, obj, forminfo): + print(obj.ordered_notes) forminfo['notes'] = [] for n in obj.ordered_notes_except_flags: author_id = n.get('author_id', '') @@ -462,13 +464,15 @@ def admin2form(cls, obj, forminfo): } forminfo['notes'].append(note_obj) + forminfo["flags"] = [] + print(obj.flags) if obj.flags: # display only the newest flag flag = obj.flags[0] flag_obj = {"flag_created_date": flag["date"], "flag_note": flag["note"], "flag_note_id": flag["id"], "flag_setter": flag["author_id"], "flag_assignee": flag["flag"]["assigned_to"], - "flag_deadline": flag["flag"]["deadline"]} - forminfo['flag'] = flag_obj + "flag_deadline": flag["flag"].get("flag_deadline", "")} + forminfo['flags'].append(flag_obj) forminfo['owner'] = obj.owner if obj.editor_group is not None: diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index 77f111c200..2751b6a71e 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -2025,10 +2025,14 @@ class FieldDefinitions: "input": "hidden" } - FLAG = { - "name": "flag", + FLAGS = { + "name": "flags", "input": "group", "label": "Flag", + "repeatable": { + "initial": 2, + "add_button_placement": "top" + }, "subfields": [ "flag_setter", "flag_created_date", @@ -2038,16 +2042,20 @@ class FieldDefinitions: "flag_setter_id", "flag_assignee" ], - "template": templates.AF_FIELD, - "entry_template": templates.AF_ENTRY_GOUP, + "template": templates.FLAGS_LIST, + "entry_template": templates.FLAG_ENTRY_GROUP, "widgets": [ - "flag_manager" + {"multiple_field": {"hide_labels": False}} + # "flag_manager" ] } # ~~->$ NoteAuthor:FormField~~ FLAG_SETTER = { "subfield": True, + "help": { + "placeholder": "setter" + }, "name": "flag_setter", "group": "flag", "input": "text", @@ -2057,6 +2065,8 @@ class FieldDefinitions: FLAG_CREATED_DATE = { "subfield": True, "name": "flag_created_date", + "help": { + "placeholder": "date"}, "group": "flag", "input": "text", } @@ -2064,6 +2074,8 @@ class FieldDefinitions: FLAG_DEADLINE = { "subfield": True, "name": "flag_deadline", + "help": { + "placeholder": "deadline"}, "group": "flag", "input": "text", } @@ -2095,6 +2107,8 @@ class FieldDefinitions: FLAG_ASSIGNEE = { "subfield": True, "name": "flag_assignee", + "help": { + "placeholder": "assigned_to"}, "group": "flag", "input": "text", "disabled": False # "disable_except_assignee_owner_admin" @@ -2377,11 +2391,11 @@ class FieldSetDefinitions: ] } - FLAG = { + FLAGS = { "name": "flag", "label": "Flag", "fields": [ - FieldDefinitions.FLAG["name"], + FieldDefinitions.FLAGS["name"], FieldDefinitions.FLAG_SETTER["name"], FieldDefinitions.FLAG_CREATED_DATE["name"], FieldDefinitions.FLAG_DEADLINE["name"], @@ -2524,7 +2538,7 @@ class ApplicationContextDefinitions: FieldSetDefinitions.REVIEWERS["name"], FieldSetDefinitions.CONTINUATIONS["name"], FieldSetDefinitions.SUBJECT["name"], - FieldSetDefinitions.FLAG["name"], + FieldSetDefinitions.FLAGS["name"], FieldSetDefinitions.NOTES["name"] ] MANED["processor"] = application_processors.AdminApplication diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index 8b03588ab4..5bcc89ec8d 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1120,10 +1120,8 @@ var formulaic = { this.init = function() { this.container = $("." + this.fieldDef.name + "__container"); - let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); - $(addFlagContainer).hide(); - // this.container.hide(); - // + this.container.hide(); + let cont = formulaic.widgets._make_empty_container(this.namespace, "autochecks", this.form, this.fieldDef); let clearFlagClass = edges.css_classes(this.namespace, "clear-flag"); let resolveFlagClass = edges.css_classes(this.namespace, "resolve-flag"); @@ -1147,16 +1145,13 @@ var formulaic = { } this.addFlag = function() { - // let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); + let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); // $(addFlagContainer).hide(); - // this.container.show(); + this.container.show(); } this.clearFlag = function() { $(this.container).find('input,textarea').val(''); - // this.container.hide(); - // let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); - // $(addFlagContainer).show(); } this.resolveFlag = function() { @@ -1784,6 +1779,10 @@ var formulaic = { MultipleField: function(params) { this.fieldDef = params.fieldDef; this.max = this.fieldDef["repeatable"]["initial"] - 1; + // this.show_labels = this.fieldDef["repeatable"]["show_labels"] ? this.fieldDef["repeatable"]["show_labels"] : false; + // if (!this.show_labels) { + // this.fields.forEach(f => f.addClass("hiddenLabel")) + // } this.init = () => { if (this.fieldDef["input"] === "group") { diff --git a/portality/templates-v2/_application-form/includes/_flag_entry.html b/portality/templates-v2/_application-form/includes/_flag_entry.html new file mode 100644 index 0000000000..1bf8ff544f --- /dev/null +++ b/portality/templates-v2/_application-form/includes/_flag_entry.html @@ -0,0 +1,6 @@ +
+

This is custom notes entry template

+ {% for subfield in f.group_subfields() %} + {{ subfield.render_form_control(wtfinst=entry[subfield.name]) }} + {% endfor %} +
diff --git a/portality/templates-v2/_application-form/includes/_flags_list.html b/portality/templates-v2/_application-form/includes/_flags_list.html new file mode 100644 index 0000000000..f4bffbdd72 --- /dev/null +++ b/portality/templates-v2/_application-form/includes/_flags_list.html @@ -0,0 +1,64 @@ +{% from "_application-form/includes/_value.html" import value %} + +
+

This is custom flag list template

+ + + {% if f.get("hint") %}

{{ f.hint | safe }}

{% endif %} + {% if f.has_widget("multiple_field") or f.has_widget("infinite_repeat") %} + {% set add_button %} +

+ +

+ {% endset %} + + {% if f.repeatable.add_button_placement == "top" %} + {{ add_button }} + {% endif %} + +
+ {% for entry in f.wtfield %} + {% set entry_template = f.entry_template %} + {% include entry_template %} + {% endfor %} +
+ + {% if f.repeatable.add_button_placement != "top" %} + {{ add_button }} + {% endif %} + + {% else %} + {% include entry_template %} + {% endif %} + + {% if f.help("render_error_box") != False %} {# some fields have custom error boxes #} +
+ {% endif %} + + {% if form_diff %} + {% if f.help("update_requests_diff", True) and f.name in form_diff %} +

+ WAS: + + {{ value(form_diff[f.name].a, f.name, formulaic_context) }} + +

+ {% endif %} + {% endif %} + + {% if f.help("short_help") %} +

{{ f.help("short_help") | safe }}

+ {% endif %} + + {% include "_application-form/includes/_modal.html" %} +
diff --git a/portality/ui/templates.py b/portality/ui/templates.py index 39d9f63b83..5df43cc03d 100644 --- a/portality/ui/templates.py +++ b/portality/ui/templates.py @@ -71,6 +71,8 @@ AF_FIELD = "_application-form/includes/_field.html" AF_GROUP = "_application-form/includes/_group.html" AF_LIST = "_application-form/includes/_list.html" +FLAGS_LIST= "_application-form/includes/_flags_list.html" +FLAG_ENTRY_GROUP = "_application-form/includes/_flag_entry.html" # Publisher area PUBLISHER_DRAFTS = "public/publisher/drafts.html" From 87631614f884ca51ab776119c9181f194c48777b Mon Sep 17 00:00:00 2001 From: amdomanska Date: Mon, 11 Nov 2024 14:34:39 +0000 Subject: [PATCH 13/94] add resolve/unresolve flag --- portality/forms/application_forms.py | 17 ++- portality/static/js/application_form.js | 11 ++ portality/static/js/formulaic.js | 100 ++++++++++++------ .../includes/_flag_entry.html | 7 +- .../includes/_flags_list.html | 56 ++-------- 5 files changed, 105 insertions(+), 86 deletions(-) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index 2751b6a71e..1ccb9093ac 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -2040,16 +2040,25 @@ class FieldDefinitions: "flag_note", "flag_note_id", "flag_setter_id", - "flag_assignee" + "flag_assignee", + "flag_resolved" ], "template": templates.FLAGS_LIST, "entry_template": templates.FLAG_ENTRY_GROUP, "widgets": [ - {"multiple_field": {"hide_labels": False}} - # "flag_manager" + "multiple_field", + "flag_manager" ] } + FLAG_RESOLVED = { + "subfield": True, + "name": "flag_resolved", + "label": "resolved", + "group": "flag", + "input": "text" + } + # ~~->$ NoteAuthor:FormField~~ FLAG_SETTER = { "subfield": True, @@ -2073,6 +2082,7 @@ class FieldDefinitions: FLAG_DEADLINE = { "subfield": True, + "optional": True, "name": "flag_deadline", "help": { "placeholder": "deadline"}, @@ -2403,6 +2413,7 @@ class FieldSetDefinitions: FieldDefinitions.FLAG_NOTE_ID["name"], FieldDefinitions.FLAG_SETTER_ID["name"], FieldDefinitions.FLAG_ASSIGNEE["name"], + FieldDefinitions.FLAG_RESOLVED["name"] ] } diff --git a/portality/static/js/application_form.js b/portality/static/js/application_form.js index 9dbdf6f609..9b91147381 100644 --- a/portality/static/js/application_form.js +++ b/portality/static/js/application_form.js @@ -569,6 +569,17 @@ doaj.af.EditorialApplicationForm = class extends doaj.af.BaseApplicationForm { }) }; + _findResolvedFlags() { + let resolvedFlags = []; + $('[id^="flags-"][id$="-flag_resolved"]').each(function() { + if ($(this).val() === 'True') { + let idx = $(this).attr('id').split('-')[1]; + resolvedFlags.push(idx); + } + }); + return resolvedFlags; + } + _generate_values_preview() { $(".admin_value_preview").each((i,elem) => { let sourceId = $(elem).attr("data-source"); diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index 5bcc89ec8d..59270ed0c8 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1120,53 +1120,87 @@ var formulaic = { this.init = function() { this.container = $("." + this.fieldDef.name + "__container"); - this.container.hide(); + let divsSelector = "div[name^='" + this.fieldDef["name"] + "__group--']"; + this.divs = $(divsSelector); + + const addFlagClassSelector = "#add_flag__" + this.fieldDef.name; + this.addFlagBtn = this.container.find(addFlagClassSelector); + + const resolveFlagBtns = $("[id^='resolve_flag--']"); + resolveFlagBtns.each((index, btn) => + $(btn).on("click", (e) => this.resolveFlag(e)) + ); + + const unresolveFlagBtns = $("[id^='unresolve_flag--']"); + unresolveFlagBtns.each((index, btn) => + $(btn).on("click", (e) => this.unresolveFlag(e)) + ); + + let inputs = this.divs.find("input[name$='-flag_assignee']"); + this.hasVal = false; + + for (var j = 0; j < inputs.length; j++) { + this.getUnresolveBtn(j).hide(); + if ($(inputs[j]).val()) { + this.hasVal = true; + this.addFlagBtn.hide(); + } + else { + this.getResolveBtn(j).hide(); + $(inputs[j]).parent().hide(); + } + } - let cont = formulaic.widgets._make_empty_container(this.namespace, "autochecks", this.form, this.fieldDef); - let clearFlagClass = edges.css_classes(this.namespace, "clear-flag"); - let resolveFlagClass = edges.css_classes(this.namespace, "resolve-flag"); - let controls = ``; - cont.html(controls); + let clearFlagClassSelector = edges.css_class_selector(this.namespace, "clear-flag"); + edges.on(clearFlagClassSelector, "click", this, "clearFlag"); - let addFlagContainer = edges.css_classes(this.namespace, "add-flag-container"); - let addFlagClass = edges.css_classes(this.namespace, "add-flag"); - let frag = `
`; - this.container.after(frag); + } - let addFlagClassSelector = edges.css_class_selector(this.namespace, "add-flag"); - edges.on(addFlagClassSelector, "click", this, "addFlag"); + this.getResolveBtn = function(idx) { + return $("[id^='resolve_flag--" + idx + "']") + } - let clearFlagClassSelector = edges.css_class_selector(this.namespace, "clear-flag"); - edges.on(clearFlagClassSelector, "click", this, "clearFlag"); + this.getUnresolveBtn = function(idx) { + return $("[id^='unresolve_flag--" + idx + "']") + } - // let resolveFlagClassSelector = edges.css_class_selector(this.namespace, "resolve-flag"); - // edges.on(resolveFlagClassSelector, "click", this, "resolveFlag"); + this.getResolvedInput = function(idx) { + return $("input[id='flags-" + idx + "-flag_resolved']") } - this.addFlag = function() { - let addFlagContainer = edges.css_class_selector(this.namespace, "add-flag-container"); - // $(addFlagContainer).hide(); - this.container.show(); + this.allowOnlyOne = function() { + } this.clearFlag = function() { $(this.container).find('input,textarea').val(''); } - this.resolveFlag = function() { - // let flagNote = this.container.find("#flag-flag_note"); - // - // let noteWidgets = formulaic.active.activeWidgets["notes"]; - // // TODO: we'll need a way to actually find the InfiniteRepeat widget for certain - // let irw = noteWidgets[0]; - // irw.addField(); - // - // let justAdded = irw.container.find("div").first(); - // let textarea = justAdded.find("textarea"); - // textarea.val("Flag resolved: " + flagNote.val()); - // - // this.clearFlag(); + this.resolveFlag = function(e) { + let flagId = e.target.id.split("--")[1]; + let resolveInput = this.getResolvedInput(flagId); + $(resolveInput).val(true); + let unresolveBtn = this.getUnresolveBtn(flagId); + $(unresolveBtn).show(); + let resolveBtn = this.getResolveBtn(flagId); + resolveBtn.hide(); + this.addFlagBtn.prop('disabled', false); + this.addFlagBtn.prop('title', "Add flag to that record"); + $(e.target).parent().addClass("resolved"); + } + + this.unresolveFlag = function(e) { + let flagId = e.target.id.split("--")[1]; + let resolveInput = this.getResolvedInput(flagId); + $(resolveInput).val(false); + let unresolveBtn = this.getUnresolveBtn(flagId); + $(unresolveBtn).hide(); + let resolveBtn = this.getResolveBtn(flagId); + resolveBtn.show(); + this.addFlagBtn.prop('disabled', true); + this.addFlagBtn.prop('title', "You can add only one flag per record. Resolve the existing flag to add another one."); + $(e.target).parent().removeClass("doaj-flag-resolved"); } this.init(); diff --git a/portality/templates-v2/_application-form/includes/_flag_entry.html b/portality/templates-v2/_application-form/includes/_flag_entry.html index 1bf8ff544f..42df6b302d 100644 --- a/portality/templates-v2/_application-form/includes/_flag_entry.html +++ b/portality/templates-v2/_application-form/includes/_flag_entry.html @@ -1,6 +1,9 @@ -
-

This is custom notes entry template

+
{% for subfield in f.group_subfields() %} {{ subfield.render_form_control(wtfinst=entry[subfield.name]) }} {% endfor %} +

+ + +

diff --git a/portality/templates-v2/_application-form/includes/_flags_list.html b/portality/templates-v2/_application-form/includes/_flags_list.html index f4bffbdd72..fc985056c4 100644 --- a/portality/templates-v2/_application-form/includes/_flags_list.html +++ b/portality/templates-v2/_application-form/includes/_flags_list.html @@ -1,64 +1,24 @@ {% from "_application-form/includes/_value.html" import value %} -
-

This is custom flag list template

+
+

+ +

- {% if f.get("hint") %}

{{ f.hint | safe }}

{% endif %} - {% if f.has_widget("multiple_field") or f.has_widget("infinite_repeat") %} - {% set add_button %} -

- -

- {% endset %} - - {% if f.repeatable.add_button_placement == "top" %} - {{ add_button }} - {% endif %} - -
- {% for entry in f.wtfield %} - {% set entry_template = f.entry_template %} - {% include entry_template %} - {% endfor %} -
- - {% if f.repeatable.add_button_placement != "top" %} - {{ add_button }} - {% endif %} - - {% else %} + {% for entry in f.wtfield %} + {% set entry_template = f.entry_template %} + {% set idx = loop.index0 %} {% include entry_template %} - {% endif %} - - {% if f.help("render_error_box") != False %} {# some fields have custom error boxes #} -
- {% endif %} - - {% if form_diff %} - {% if f.help("update_requests_diff", True) and f.name in form_diff %} -

- WAS: - - {{ value(form_diff[f.name].a, f.name, formulaic_context) }} - -

- {% endif %} - {% endif %} + {% endfor %} {% if f.help("short_help") %}

{{ f.help("short_help") | safe }}

{% endif %} - {% include "_application-form/includes/_modal.html" %}
From 0b29b964407ad42fae466e9d2af2ffd2cbd4617e Mon Sep 17 00:00:00 2001 From: amdomanska Date: Mon, 11 Nov 2024 14:46:29 +0000 Subject: [PATCH 14/94] change resolved flag into the note --- portality/crosswalks/journal_form.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/portality/crosswalks/journal_form.py b/portality/crosswalks/journal_form.py index a1ffdac870..d371778856 100644 --- a/portality/crosswalks/journal_form.py +++ b/portality/crosswalks/journal_form.py @@ -271,7 +271,6 @@ def form2admin(cls, form, obj): author_id=formnote["note_author_id"]) if getattr(form, "flags", None): - print(form.flags.data) flag = form.flags.data[0] flag_date = flag["flag_created_date"] flag_deadline = flag["flag_deadline"] @@ -279,7 +278,16 @@ def form2admin(cls, form, obj): flag_author = flag["flag_setter"] flag_id = flag["flag_note_id"] flag_note = flag["flag_note"] - obj.add_note(flag_note, date=flag_date, id=flag_id, + flag_resolved = flag["flag_resolved"] + flag_resolved_by = "Myself" + flag_resolved_date = "today" + print(flag_resolved) + if flag_resolved == "true": + note = f"Flag: \n Resolved by: {flag_resolved_by} \n Resolved on: {flag_resolved_date}\n Assigned to: {flag_assigned_to} \n Note: {flag_note}" + print(note) + obj.add_note(note, date=flag_date, id=flag_id, author_id=flag_author) + else: + obj.add_note(flag_note, date=flag_date, id=flag_id, author_id=flag_author, assigned_to=flag_assigned_to, deadline=flag_deadline) if getattr(form, 'owner', None): From b68c9c169497ff42d6d977130acb8af3f0987cc4 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Mon, 11 Nov 2024 22:45:10 +0000 Subject: [PATCH 15/94] only one flag ensured; buttons disabled and enabled correctly; resolving the flag and adding new works great --- portality/static/js/application_form.js | 11 - portality/static/js/formulaic.js | 201 ++++++++++++++---- .../includes/_flag_entry.html | 10 +- 3 files changed, 167 insertions(+), 55 deletions(-) diff --git a/portality/static/js/application_form.js b/portality/static/js/application_form.js index 9b91147381..9dbdf6f609 100644 --- a/portality/static/js/application_form.js +++ b/portality/static/js/application_form.js @@ -569,17 +569,6 @@ doaj.af.EditorialApplicationForm = class extends doaj.af.BaseApplicationForm { }) }; - _findResolvedFlags() { - let resolvedFlags = []; - $('[id^="flags-"][id$="-flag_resolved"]').each(function() { - if ($(this).val() === 'True') { - let idx = $(this).attr('id').split('-')[1]; - resolvedFlags.push(idx); - } - }); - return resolvedFlags; - } - _generate_values_preview() { $(".admin_value_preview").each((i,elem) => { let sourceId = $(elem).attr("data-source"); diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index 59270ed0c8..8b750a0f95 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1119,12 +1119,65 @@ var formulaic = { this.namespace = "formulaic-flagmanager-" + this.fieldDef.name; this.init = function() { + //for debugging purposes only + let style = document.createElement("style"); + style.innerHTML = ` + .flag--resolved { + position: relative; + opacity: 0.2; /* Set opacity of entire div */ + } + + .flag--resolved button { + position: relative; /* Keep the button unaffected by opacity */ + z-index: 1; /* Ensure the button is above the stamp effect */ + } + + .flag--resolved::before { + content: "RESOLVED"; /* The word to display as the stamp */ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) rotate(-45deg); /* Center and rotate the text */ + font-size: 3em; /* Adjust the size of the stamp */ + color: rgba(0, 0, 0, 0.5); /* Light black color for the stamp */ + z-index: 0; /* Place the stamp behind the button */ + pointer-events: none; /* Ensure the stamp doesn't interfere with interactions */ + opacity: 0.6; /* Make the stamp slightly transparent */ + letter-spacing: 0.2em; /* Adjust the spacing between letters for the stamp */ + font-weight: bold; + } + + `; + + // Append the style to the head + document.head.appendChild(style); + + this.container = $("." + this.fieldDef.name + "__container"); - let divsSelector = "div[name^='" + this.fieldDef["name"] + "__group--']"; - this.divs = $(divsSelector); + this.flagGroups = $("div[name^='" + this.fieldDef["name"] + "__group--']"); + this.flagInputsContainer = $("div[name^='" + this.fieldDef["name"] + "-inputs--container--']"); + + this.flagExists = false; + this.existingFlagIdx = null; + this.newFlagIdx = null; + + this.setUpEventListeners(); + + let inputs = this.flagGroups.find("input[name$='-flag_assignee']"); + + for (var j = 0; j < inputs.length; j++) { + if ($(inputs[j]).val()) { + this.flagExists = true; + } + } + + this.setUI(); + } + this.setUpEventListeners = function() { const addFlagClassSelector = "#add_flag__" + this.fieldDef.name; this.addFlagBtn = this.container.find(addFlagClassSelector); + $(this.addFlagBtn).on("click", () => this.addFlag()) const resolveFlagBtns = $("[id^='resolve_flag--']"); resolveFlagBtns.each((index, btn) => @@ -1136,25 +1189,25 @@ var formulaic = { $(btn).on("click", (e) => this.unresolveFlag(e)) ); - let inputs = this.divs.find("input[name$='-flag_assignee']"); - this.hasVal = false; - - for (var j = 0; j < inputs.length; j++) { - this.getUnresolveBtn(j).hide(); - if ($(inputs[j]).val()) { - this.hasVal = true; - this.addFlagBtn.hide(); - } - else { - this.getResolveBtn(j).hide(); - $(inputs[j]).parent().hide(); - } - } + let clearFlagClassBtns = $("[id^='clearFlag--']"); + clearFlagClassBtns.each((index, btn) => + $(btn).on("click", (e) => this.clearFlag(e)) + ); + let cancelFlagBtns = $("[id^='cancelAddingFlag--']"); + cancelFlagBtns.each((index, btn) => + $(btn).on("click", (e) => this.cancelFlag(e)) + ); + } - let clearFlagClassSelector = edges.css_class_selector(this.namespace, "clear-flag"); - edges.on(clearFlagClassSelector, "click", this, "clearFlag"); + this.enableAddBtn = function() { + $(this.addFlagBtn).prop('disabled', false); + $(this.addFlagBtn).prop('title', "Add flag to that record"); + } + this.disableAddBtn = function() { + $(this.addFlagBtn).prop('disabled', true); + $(this.addFlagBtn).prop('title', "You can add only one flag per record. Resolve the existing flag to add another one."); } this.getResolveBtn = function(idx) { @@ -1169,38 +1222,104 @@ var formulaic = { return $("input[id='flags-" + idx + "-flag_resolved']") } - this.allowOnlyOne = function() { + this.getClearFlagBtn = function(idx) { + return $("button[id='clearFlag--" + idx + "']"); + } + + this.getCancelFlagBtn = function(idx) { + return $("button[id='cancelAddingFlag--" + idx + "']") + } + + this.clearFlag = function(e) { + let flagId = e.target.id.split("--")[1]; + $(this.flagGroups[flagId]).find('input,textarea').val(''); + } + + this.setUI = function() { + // Calculate indices based on the flag's existence + this.existingFlagIdx = this.flagExists ? 0 : null; + this.newFlagIdx = this.flagExists ? 1 : 0; + + if (this.flagExists) { + this.getResolveBtn(this.existingFlagIdx).show(); + this.getUnresolveBtn(this.existingFlagIdx).hide(); + this.getCancelFlagBtn(this.existingFlagIdx).hide(); + this.getClearFlagBtn(this.existingFlagIdx).hide(); + $(this.flagGroups[this.newFlagIdx]).insertBefore(this.flagGroups[this.existingFlagIdx]); + } + else { + $(this.flagGroups[1]).hide(); + } + + this.getResolveBtn(this.newFlagIdx).hide(); + this.getUnresolveBtn(this.newFlagIdx).hide(); + this.getCancelFlagBtn(this.newFlagIdx).show(); + this.getClearFlagBtn(this.newFlagIdx).show(); + $(this.flagGroups[this.newFlagIdx]).hide(); + + this.setAddBtnStatus(); + }; + + this.setAddBtnStatus = function() { + if (this.flagExists) { + this.disableAddBtn(); + } + else { + this.enableAddBtn(); + } + } + + this.showNewFlag = function() { + $(this.flagGroups[this.newFlagIdx]).show(); + } + + this.hideNewFlag = function() { + $(this.flagGroups[this.newFlagIdx]).hide(); + } + + this.markFlagAsResolved = function() { + $(this.flagInputsContainer[this.existingFlagIdx]).addClass("flag--resolved"); + this.getResolveBtn(this.existingFlagIdx).hide(); + this.getUnresolveBtn(this.existingFlagIdx).show(); + } + this.markFlagAsUnresolved = function() { + $(this.flagInputsContainer[this.existingFlagIdx]).removeClass("flag--resolved"); + this.getResolveBtn(this.existingFlagIdx).show(); + this.getUnresolveBtn(this.existingFlagIdx).hide(); } - this.clearFlag = function() { - $(this.container).find('input,textarea').val(''); + this.addFlag = function() { + this.showNewFlag(); + this.flagExists = true; + this.setAddBtnStatus(); + if (this.existingFlagIdx !== null) { + this.getUnresolveBtn(this.existingFlagIdx).prop("disabled", true); + this.getUnresolveBtn(this.existingFlagIdx).prop("title", "You can add only one flag at the time. To unresolve this flag, remove the new flag first"); + } + } + + this.cancelFlag = function(idx) { + this.hideNewFlag(); + this.flagExists = false; + this.setAddBtnStatus(); + if (this.existingFlagIdx !== null) { + this.getUnresolveBtn(this.existingFlagIdx).prop("disabled", false); + this.getUnresolveBtn(this.existingFlagIdx).prop("title", ""); + } } this.resolveFlag = function(e) { - let flagId = e.target.id.split("--")[1]; - let resolveInput = this.getResolvedInput(flagId); - $(resolveInput).val(true); - let unresolveBtn = this.getUnresolveBtn(flagId); - $(unresolveBtn).show(); - let resolveBtn = this.getResolveBtn(flagId); - resolveBtn.hide(); - this.addFlagBtn.prop('disabled', false); - this.addFlagBtn.prop('title', "Add flag to that record"); - $(e.target).parent().addClass("resolved"); + this.markFlagAsResolved(); + this.flagExists = false; + this.setAddBtnStatus(); } this.unresolveFlag = function(e) { - let flagId = e.target.id.split("--")[1]; - let resolveInput = this.getResolvedInput(flagId); - $(resolveInput).val(false); - let unresolveBtn = this.getUnresolveBtn(flagId); - $(unresolveBtn).hide(); - let resolveBtn = this.getResolveBtn(flagId); - resolveBtn.show(); - this.addFlagBtn.prop('disabled', true); - this.addFlagBtn.prop('title', "You can add only one flag per record. Resolve the existing flag to add another one."); - $(e.target).parent().removeClass("doaj-flag-resolved"); + // let flagId = e.target.id.split("--")[1]; + this.markFlagAsUnresolved(); + this.flagExists = true; + this.setAddBtnStatus(); } this.init(); diff --git a/portality/templates-v2/_application-form/includes/_flag_entry.html b/portality/templates-v2/_application-form/includes/_flag_entry.html index 42df6b302d..ffcc06d646 100644 --- a/portality/templates-v2/_application-form/includes/_flag_entry.html +++ b/portality/templates-v2/_application-form/includes/_flag_entry.html @@ -1,9 +1,13 @@
- {% for subfield in f.group_subfields() %} - {{ subfield.render_form_control(wtfinst=entry[subfield.name]) }} - {% endfor %} +
+ {% for subfield in f.group_subfields() %} + {{ subfield.render_form_control(wtfinst=entry[subfield.name]) }} + {% endfor %} +

+ +

From b711329a360961ef33fb3808fff102d927fef91a Mon Sep 17 00:00:00 2001 From: amdomanska Date: Mon, 11 Nov 2024 23:32:48 +0000 Subject: [PATCH 16/94] now backend handled resolving and adding well --- portality/crosswalks/journal_form.py | 37 ++++++++++++++-------------- portality/static/js/formulaic.js | 6 +++++ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/portality/crosswalks/journal_form.py b/portality/crosswalks/journal_form.py index d371778856..c0b8c806ac 100644 --- a/portality/crosswalks/journal_form.py +++ b/portality/crosswalks/journal_form.py @@ -271,24 +271,24 @@ def form2admin(cls, form, obj): author_id=formnote["note_author_id"]) if getattr(form, "flags", None): - flag = form.flags.data[0] - flag_date = flag["flag_created_date"] - flag_deadline = flag["flag_deadline"] - flag_assigned_to = flag["flag_assignee"] - flag_author = flag["flag_setter"] - flag_id = flag["flag_note_id"] - flag_note = flag["flag_note"] - flag_resolved = flag["flag_resolved"] - flag_resolved_by = "Myself" - flag_resolved_date = "today" - print(flag_resolved) - if flag_resolved == "true": - note = f"Flag: \n Resolved by: {flag_resolved_by} \n Resolved on: {flag_resolved_date}\n Assigned to: {flag_assigned_to} \n Note: {flag_note}" - print(note) - obj.add_note(note, date=flag_date, id=flag_id, author_id=flag_author) - else: - obj.add_note(flag_note, date=flag_date, id=flag_id, - author_id=flag_author, assigned_to=flag_assigned_to, deadline=flag_deadline) + for flag in form.flags.data: + flag_date = flag["flag_created_date"] + flag_deadline = flag["flag_deadline"] + flag_assigned_to = flag["flag_assignee"] + flag_author = flag["flag_setter"] + flag_id = flag["flag_note_id"] + flag_note = flag["flag_note"] + flag_resolved = flag["flag_resolved"] + flag_resolved_by = "Myself" + flag_resolved_date = "today" + if flag_resolved == "true": + # obj.remove_note({"id": flag_id}) + note = f"Flag: \n Resolved by: {flag_resolved_by} \n Resolved on: {flag_resolved_date}\n Assigned to: {flag_assigned_to} \n Note: {flag_note}" + obj.add_note(note, date=flag_date, id=flag_id, author_id=flag_author) + else: + obj.add_note(flag_note, date=flag_date, id=flag_id, + author_id=flag_author, assigned_to=flag_assigned_to, deadline=flag_deadline) + print(obj.flags) if getattr(form, 'owner', None): owner = form.owner.data @@ -461,7 +461,6 @@ def bibjson2form(cls, bibjson, forminfo): @classmethod def admin2form(cls, obj, forminfo): - print(obj.ordered_notes) forminfo['notes'] = [] for n in obj.ordered_notes_except_flags: author_id = n.get('author_id', '') diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index 8b750a0f95..0e8369c35a 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1230,6 +1230,10 @@ var formulaic = { return $("button[id='cancelAddingFlag--" + idx + "']") } + this.getResolveFlagInput = function(idx) { + return $("input[id='flags-" + idx + "-flag_resolved']") + } + this.clearFlag = function(e) { let flagId = e.target.id.split("--")[1]; $(this.flagGroups[flagId]).find('input,textarea').val(''); @@ -1311,6 +1315,7 @@ var formulaic = { this.resolveFlag = function(e) { this.markFlagAsResolved(); + this.getResolveFlagInput(this.existingFlagIdx).val("true"); this.flagExists = false; this.setAddBtnStatus(); } @@ -1318,6 +1323,7 @@ var formulaic = { this.unresolveFlag = function(e) { // let flagId = e.target.id.split("--")[1]; this.markFlagAsUnresolved(); + this.getResolveFlagInput().val("false"); this.flagExists = true; this.setAddBtnStatus(); } From 0e0873d0391d7bcfe40e6968bc401a2ec2d4e510 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Tue, 12 Nov 2024 00:14:10 +0000 Subject: [PATCH 17/94] automatic resolved by and resolved_on --- portality/crosswalks/journal_form.py | 14 +++++++++----- portality/forms/application_forms.py | 6 ++++-- portality/static/js/formulaic.js | 2 ++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/portality/crosswalks/journal_form.py b/portality/crosswalks/journal_form.py index c0b8c806ac..35a9c959df 100644 --- a/portality/crosswalks/journal_form.py +++ b/portality/crosswalks/journal_form.py @@ -4,6 +4,10 @@ from portality.datasets import licenses from portality.forms.utils import expanded2compact from portality.models import Account +from portality.lib import dates + +from flask_login import current_user + class JournalGenericXWalk(object): @@ -279,10 +283,9 @@ def form2admin(cls, form, obj): flag_id = flag["flag_note_id"] flag_note = flag["flag_note"] flag_resolved = flag["flag_resolved"] - flag_resolved_by = "Myself" - flag_resolved_date = "today" + flag_resolved_by = current_user.id if current_user else "" + flag_resolved_date = dates.now_str() if flag_resolved == "true": - # obj.remove_note({"id": flag_id}) note = f"Flag: \n Resolved by: {flag_resolved_by} \n Resolved on: {flag_resolved_date}\n Assigned to: {flag_assigned_to} \n Note: {flag_note}" obj.add_note(note, date=flag_date, id=flag_id, author_id=flag_author) else: @@ -472,12 +475,13 @@ def admin2form(cls, obj, forminfo): forminfo['notes'].append(note_obj) forminfo["flags"] = [] - print(obj.flags) if obj.flags: # display only the newest flag flag = obj.flags[0] + author_id = flag["author_id"] + flag_setter = f'{Account.get_name_safe(author_id)} ({author_id})' if author_id else '' flag_obj = {"flag_created_date": flag["date"], "flag_note": flag["note"], "flag_note_id": flag["id"], - "flag_setter": flag["author_id"], "flag_assignee": flag["flag"]["assigned_to"], + "flag_setter": flag_setter, "flag_assignee": flag["flag"]["assigned_to"], "flag_deadline": flag["flag"].get("flag_deadline", "")} forminfo['flags'].append(flag_obj) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index 1ccb9093ac..f33475aa5b 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -2054,9 +2054,8 @@ class FieldDefinitions: FLAG_RESOLVED = { "subfield": True, "name": "flag_resolved", - "label": "resolved", "group": "flag", - "input": "text" + "input": "hidden" } # ~~->$ NoteAuthor:FormField~~ @@ -2120,6 +2119,9 @@ class FieldDefinitions: "help": { "placeholder": "assigned_to"}, "group": "flag", + "validate": [ + "required" + ], "input": "text", "disabled": False # "disable_except_assignee_owner_admin" } diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index 0e8369c35a..df063dfe56 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1259,6 +1259,8 @@ var formulaic = { this.getUnresolveBtn(this.newFlagIdx).hide(); this.getCancelFlagBtn(this.newFlagIdx).show(); this.getClearFlagBtn(this.newFlagIdx).show(); + $("#flags-" + this.newFlagIdx + "-flag_setter").hide(); + $("#flags-" + this.newFlagIdx + "-flag_created_date").hide(); $(this.flagGroups[this.newFlagIdx]).hide(); this.setAddBtnStatus(); From 0ff3317359be1154c0e4186e00cfe33f2b9ca07f Mon Sep 17 00:00:00 2001 From: amdomanska Date: Tue, 12 Nov 2024 00:41:04 +0000 Subject: [PATCH 18/94] add accounts to assigned_to --- portality/forms/application_forms.py | 7 ++++++- portality/static/js/formulaic.js | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index f33475aa5b..d522e6f05e 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -2120,7 +2120,12 @@ class FieldDefinitions: "placeholder": "assigned_to"}, "group": "flag", "validate": [ - "required" + {"required": {"message": "A flag must be assigned to a user."}}, + "reserved_usernames", + "owner_exists" + ], + "widgets": [ + {"autocomplete": {"type": "account", "field": "id", "include": False}}, # ~~^-> Autocomplete:FormWidget~~ ], "input": "text", "disabled": False # "disable_except_assignee_owner_admin" diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index df063dfe56..c19c60b047 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -2400,7 +2400,13 @@ var formulaic = { callback(data); }; - let selector = "[name='" + this.fieldDef.name + "']"; + let selector = "" + if (this.fieldDef.group){ + selector = "[name$='" + this.fieldDef.name + "']"; + } + else { + selector = "[name='" + this.fieldDef.name + "']"; + } $(selector).on("focus", formulaic.widgets._select2_shift_focus); From 41b0759aeeab239c3e390cdd8d823b5d794033f2 Mon Sep 17 00:00:00 2001 From: amdomanska Date: Tue, 12 Nov 2024 01:04:36 +0000 Subject: [PATCH 19/94] add labels and change the order --- portality/forms/application_forms.py | 9 ++++++--- .../_application-form/includes/_flag_entry.html | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index d522e6f05e..8be0b844b3 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -2034,13 +2034,13 @@ class FieldDefinitions: "add_button_placement": "top" }, "subfields": [ + "flag_assignee", + "flag_note", + "flag_deadline", "flag_setter", "flag_created_date", - "flag_deadline", - "flag_note", "flag_note_id", "flag_setter_id", - "flag_assignee", "flag_resolved" ], "template": templates.FLAGS_LIST, @@ -2082,6 +2082,7 @@ class FieldDefinitions: FLAG_DEADLINE = { "subfield": True, "optional": True, + "label": "Deadline", "name": "flag_deadline", "help": { "placeholder": "deadline"}, @@ -2092,6 +2093,7 @@ class FieldDefinitions: FLAG_NOTE = { "subfield": True, "name": "flag_note", + "label": "Note", "group": "flag", "input": "textarea", "disabled": False # "disable_except_assignee_owner_admin", @@ -2116,6 +2118,7 @@ class FieldDefinitions: FLAG_ASSIGNEE = { "subfield": True, "name": "flag_assignee", + "label": "Assign a user", "help": { "placeholder": "assigned_to"}, "group": "flag", diff --git a/portality/templates-v2/_application-form/includes/_flag_entry.html b/portality/templates-v2/_application-form/includes/_flag_entry.html index ffcc06d646..8e844c2cd7 100644 --- a/portality/templates-v2/_application-form/includes/_flag_entry.html +++ b/portality/templates-v2/_application-form/includes/_flag_entry.html @@ -1,6 +1,7 @@
{% for subfield in f.group_subfields() %} + {{ subfield.render_form_control(wtfinst=entry[subfield.name]) }} {% endfor %}
From cb8139d9a35bcee13594f1de349fa70ec842363f Mon Sep 17 00:00:00 2001 From: amdomanska Date: Tue, 12 Nov 2024 12:08:12 +0000 Subject: [PATCH 20/94] control who can add the field --- portality/forms/application_forms.py | 5 ++++- portality/models/v2/journal.py | 14 +++++++++++--- portality/models/v2/shared_structs.py | 3 ++- portality/static/js/formulaic.js | 4 ---- .../_application-form/includes/_flags_list.html | 16 +++++++++++++--- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/portality/forms/application_forms.py b/portality/forms/application_forms.py index 8be0b844b3..a80dd0fa5c 100644 --- a/portality/forms/application_forms.py +++ b/portality/forms/application_forms.py @@ -2031,7 +2031,8 @@ class FieldDefinitions: "label": "Flag", "repeatable": { "initial": 2, - "add_button_placement": "top" + "add_button_placement": "top", + "add_field_permission": ["admin"] }, "subfields": [ "flag_assignee", @@ -2527,6 +2528,7 @@ class ApplicationContextDefinitions: ASSOCIATE["fieldsets"] += [ FieldSetDefinitions.STATUS["name"], FieldSetDefinitions.SUBJECT["name"], + FieldSetDefinitions.FLAGS["name"], FieldSetDefinitions.NOTES["name"] ] ASSOCIATE["processor"] = application_processors.AssociateApplication @@ -2541,6 +2543,7 @@ class ApplicationContextDefinitions: FieldSetDefinitions.STATUS["name"], FieldSetDefinitions.REVIEWERS["name"], FieldSetDefinitions.SUBJECT["name"], + FieldSetDefinitions.FLAGS["name"], FieldSetDefinitions.NOTES["name"] ] EDITOR["processor"] = application_processors.EditorApplication diff --git a/portality/models/v2/journal.py b/portality/models/v2/journal.py index 0322cd525c..e73b5dcf49 100644 --- a/portality/models/v2/journal.py +++ b/portality/models/v2/journal.py @@ -397,7 +397,8 @@ def _generate_index(self): continued = "No" has_editor_group = "No" has_editor = "No" - has_flag = False + is_flagged = "No" + flag_assignees = None # the places we're going to get those fields from cbib = self.bibjson() @@ -441,7 +442,12 @@ def _generate_index(self): license.append(l.get("type")) # check for any flags - has_flag = any("assigned_to" in note.get("flag", {}) and note["flag"]["assigned_to"] is not None for note in self.notes) + is_flagged = any("assigned_to" in note.get("flag", {}) and note["flag"]["assigned_to"] is not None for note in self.notes) + flag_assignees = [ + note["flag"]["assigned_to"] + for note in self.notes + if "assigned_to" in note.get("flag", {}) and note["flag"]["assigned_to"] + ] # deduplicate the lists titles = list(set(titles)) @@ -488,7 +494,9 @@ def _generate_index(self): index["unpunctitle"] = unpunctitle if asciiunpunctitle is not None: index["asciiunpunctitle"] = asciiunpunctitle - index["has_flag"] = has_flag + if is_flagged: + index["is_flagged"] = is_flagged + index["flag_assignees"] = flag_assignees index["continued"] = continued index["has_editor_group"] = has_editor_group index["has_editor"] = has_editor diff --git a/portality/models/v2/shared_structs.py b/portality/models/v2/shared_structs.py index 5996792528..048717e955 100644 --- a/portality/models/v2/shared_structs.py +++ b/portality/models/v2/shared_structs.py @@ -228,7 +228,8 @@ "country" : {"coerce" : "unicode"}, "has_apc" : {"coerce" : "unicode"}, "has_seal" : {"coerce" : "unicode"}, - "has_flag" : {"coerce" : "unicode"}, + "is_flagged" : {"coerce" : "unicode"}, + "flag_assignees" : {"coerce" : "unicode"}, "unpunctitle" : {"coerce" : "unicode"}, "asciiunpunctitle" : {"coerce" : "unicode"}, "continued" : {"coerce" : "unicode"}, diff --git a/portality/static/js/formulaic.js b/portality/static/js/formulaic.js index c19c60b047..652ffa5423 100644 --- a/portality/static/js/formulaic.js +++ b/portality/static/js/formulaic.js @@ -1940,10 +1940,6 @@ var formulaic = { MultipleField: function(params) { this.fieldDef = params.fieldDef; this.max = this.fieldDef["repeatable"]["initial"] - 1; - // this.show_labels = this.fieldDef["repeatable"]["show_labels"] ? this.fieldDef["repeatable"]["show_labels"] : false; - // if (!this.show_labels) { - // this.fields.forEach(f => f.addClass("hiddenLabel")) - // } this.init = () => { if (this.fieldDef["input"] === "group") { diff --git a/portality/templates-v2/_application-form/includes/_flags_list.html b/portality/templates-v2/_application-form/includes/_flags_list.html index fc985056c4..64932d5d15 100644 --- a/portality/templates-v2/_application-form/includes/_flags_list.html +++ b/portality/templates-v2/_application-form/includes/_flags_list.html @@ -2,9 +2,19 @@
-

- -

+ {% set role_found = false %} + {% for role in f.repeatable.add_field_permission | default([]) %} + {% if current_user.has_role(role) %} + {% set role_found = true %} + {# Exit the loop early if a matching role is found #} + {% break %} + {% endif %} + {% endfor %} + {% if role_found %} +

+ +

+ {% endif %}