From 06e3f44e5743ee3e406f924208efa5ba909f5f59 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 12 Jan 2024 10:41:43 -0500 Subject: [PATCH 1/7] Remove hard-coded sample name on backend #1516 --- .../analysis-areas-annotation-step.js | 3 +-- arches_for_science/tests.py | 20 +++++++------- .../views/analysis_area_and_sample_taking.py | 26 +++++++++---------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js index 9b8b06799..24d3287ab 100644 --- a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js +++ b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js @@ -410,7 +410,6 @@ define([ parentPhysicalThingTileData: koMapping.toJSON(parentPhysicalThing.data), parentPhysicalThingTileId: parentPhysicalThing.tileid, transactionId: params.form.workflowId, - analysisAreaName: self.areaName() }; self.savingTile(true); @@ -504,12 +503,12 @@ define([ const data = { parentPhysicalThingResourceid: self.physicalThingResourceId, + parentPhysicalThingName: self.physicalThingName(), collectionResourceid: params.projectSet, partIdentifierAssignmentTileData: koMapping.toJSON(self.selectedAnalysisAreaInstance().data), partIdentifierAssignmentTileId: self.selectedAnalysisAreaInstance().tileid, partIdentifierAssignmentResourceId: self.selectedAnalysisAreaInstance().resourceinstance_id, transactionId: params.form.workflowId, - analysisAreaName: self.areaName(), }; $.ajax({ diff --git a/arches_for_science/tests.py b/arches_for_science/tests.py index c051396c6..13c758afb 100644 --- a/arches_for_science/tests.py +++ b/arches_for_science/tests.py @@ -13,6 +13,7 @@ PHYSICAL_THING_GRAPH_ID = "9519cb4f-b25b-11e9-8c7b-a4d18cec433a" PART_IDENTIFIER_ASSIGNMENT = "b240c366-8594-11ea-97eb-acde48001122" +PART_IDENTIFIER_ASSIGNMENT_LABEL = "3e541cc6-859b-11ea-97eb-acde48001122" SAMPLING_ACTIVITY_GRAPH_ID = "03357848-1d9d-11eb-a29f-024e0d439fdb" COLLECTION_RESOURCE = "54bf1022-a0b8-4f95-a5e9-82c084b2f533" # arbitrary test value @@ -58,10 +59,14 @@ def test_create_delete_analysis_area(self): create_data = { "transaction_id": transaction_id, # NB: snake_case "parentPhysicalThingResourceid": str(parent_phys_thing.pk), # NB: lowercase id + "parentPhysicalThingName": "Test Name of Physical Thing", "collectionResourceid": COLLECTION_RESOURCE, - "partIdentifierAssignmentTileData": JSONSerializer().serialize( - {PART_IDENTIFIER_ASSIGNMENT: []} - ), + "partIdentifierAssignmentTileData": JSONSerializer().serialize({ + PART_IDENTIFIER_ASSIGNMENT: [], + PART_IDENTIFIER_ASSIGNMENT_LABEL: { + get_language(): {"value": "test value", "direction": "ltr"}, + }, + }), "analysisAreaName": "Test Analysis Area", } response = client.post(reverse("saveanalysisarea"), create_data) @@ -101,14 +106,12 @@ def test_create_delete_sample(self): part = self.get_resource_instance(PHYSICAL_THING_GRAPH_ID) # Create - physical_part_of_object_nodeid = "b240c366-8594-11ea-97eb-acde48001122" - part_identifier_assignment_label_nodeid = "3e541cc6-859b-11ea-97eb-acde48001122" part_identifier_assignment_polygon_identifier_nodeid = "97c30c42-8594-11ea-97eb-acde48001122" part_identifier_assignment_tile_data = { - part_identifier_assignment_label_nodeid: { + PART_IDENTIFIER_ASSIGNMENT_LABEL: { get_language(): {"value": "test value", "direction": "ltr"} }, - physical_part_of_object_nodeid: [], + PART_IDENTIFIER_ASSIGNMENT: [], part_identifier_assignment_polygon_identifier_nodeid: {}, } @@ -128,7 +131,7 @@ def test_create_delete_sample(self): # Delete result = response.json()['result'] - physical_part_of_object_nodeid = "b240c366-8594-11ea-97eb-acde48001122" + physical_part_of_object_nodeid = PART_IDENTIFIER_ASSIGNMENT physical_part_of_object_resourceid = result['parentPhysicalThing']['physicalPartOfObjectTile']['data'][physical_part_of_object_nodeid][0]['resourceId'] part_identifier_assignment_tile_data = { **part_identifier_assignment_tile_data, @@ -140,7 +143,6 @@ def test_create_delete_sample(self): delete_data = { "transactionId": transaction_id, # NB: camelCase "parentPhysicalThingResourceid": str(parent_phys_thing.pk), - "parentPhysicalThingName": "Test Name of Physical Thing", "partIdentifierAssignmentTileData": JSONSerializer().serialize(part_identifier_assignment_tile_data), "samplingActivityResourceId": str(sampling_activity.pk), "collectionResourceid": COLLECTION_RESOURCE, diff --git a/arches_for_science/views/analysis_area_and_sample_taking.py b/arches_for_science/views/analysis_area_and_sample_taking.py index 4005544ad..0a527569f 100644 --- a/arches_for_science/views/analysis_area_and_sample_taking.py +++ b/arches_for_science/views/analysis_area_and_sample_taking.py @@ -1,6 +1,5 @@ -import json import logging -from django.core.exceptions import ObjectDoesNotExist, ValidationError +from django.core.exceptions import ObjectDoesNotExist from django.db import transaction from django.utils.decorators import method_decorator from django.utils.translation import gettext as _ @@ -177,18 +176,20 @@ class SaveAnalysisAreaView(SaveAnnotationView): def post(self, request): parent_physical_thing_resourceid = request.POST.get("parentPhysicalThingResourceid") + parent_physical_thing_name = request.POST.get("parentPhysicalThingName") collection_resourceid = request.POST.get("collectionResourceid") transaction_id = request.POST.get("transactionId") part_identifier_assignment_tile_data = JSONDeserializer().deserialize(request.POST.get("partIdentifierAssignmentTileData")) part_identifier_assignment_tile_id = request.POST.get("partIdentifierAssignmentTileId") or None - name = request.POST.get("analysisAreaName") - if not name: - raise ValidationError(_("Name is required.")) + part_identifier_assignment_label_nodeid = "3e541cc6-859b-11ea-97eb-acde48001122" physical_part_of_object_nodeid = "b240c366-8594-11ea-97eb-acde48001122" analysis_area_physical_thing_resourceid = None if part_identifier_assignment_tile_data[physical_part_of_object_nodeid]: analysis_area_physical_thing_resourceid = part_identifier_assignment_tile_data[physical_part_of_object_nodeid][0]["resourceId"] + base_name = part_identifier_assignment_tile_data[part_identifier_assignment_label_nodeid][get_language()]["value"] + name = _("{} [Analysis Area of {}]").format(base_name, parent_physical_thing_name) + try: with transaction.atomic(): if analysis_area_physical_thing_resourceid is None: @@ -359,10 +360,9 @@ def post(self, request): sample_physical_thing_resourceid = None sampling_unit_tiles = Tile.objects.filter(resourceinstance=sampling_activity_resourceid, nodegroup=sampling_unit_nodegroupid) - if len(sampling_unit_tiles) > 0: - for sampling_unit_tile in sampling_unit_tiles: - if sampling_unit_tile.data[sampling_area_nodeid][0]["resourceId"] == sample_area_physical_thing_resourceid: - sample_physical_thing_resourceid = sampling_unit_tile.data[sampling_area_sample_created_nodeid][0]["resourceId"] + for sampling_unit_tile in sampling_unit_tiles: + if sampling_unit_tile.data[sampling_area_nodeid][0]["resourceId"] == sample_area_physical_thing_resourceid: + sample_physical_thing_resourceid = sampling_unit_tile.data[sampling_area_sample_created_nodeid][0]["resourceId"] base_name = part_identifier_assignment_tile_data[part_identifier_assignment_label_nodeid][get_language()]["value"] sample_name = _("{} [Sample of {}]").format(base_name, parent_physical_thing_name) @@ -498,7 +498,6 @@ def post(self, request): sampling_unit_nodegroupid = "b3e171a7-1d9d-11eb-a29f-024e0d439fdb" parent_physical_thing_resourceid = data.get("parentPhysicalThingResourceid") - parent_physical_thing_name = data.get("parentPhysicalThingName") sampling_activity_resourceid = data.get("samplingActivityResourceId") collection_resourceid = data.get("collectionResourceid") sample_motivation = data.get("sampleMotivation") @@ -515,10 +514,9 @@ def post(self, request): try: sample_physical_thing_resourceid = None sampling_unit_tiles = Tile.objects.filter(resourceinstance_id=sampling_activity_resourceid, nodegroup=sampling_unit_nodegroupid) - if len(sampling_unit_tiles) > 0: - for sampling_unit_tile in sampling_unit_tiles: - if sampling_unit_tile.data[sampling_area_nodeid][0]["resourceId"] == sample_area_physical_thing_resourceid: - sample_physical_thing_resourceid = sampling_unit_tile.data[sampling_area_sample_created_nodeid][0]["resourceId"] + for sampling_unit_tile in sampling_unit_tiles: + if sampling_unit_tile.data[sampling_area_nodeid][0]["resourceId"] == sample_area_physical_thing_resourceid: + sample_physical_thing_resourceid = sampling_unit_tile.data[sampling_area_sample_created_nodeid][0]["resourceId"] parentPhysicalThingSampleTile = ResourceXResource.objects.get( nodeid=physical_part_of_object_nodeid, From ab628ad3b01b315d4a0fbfe202e427d06d5942c9 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 12 Jan 2024 11:15:45 -0500 Subject: [PATCH 2/7] Remove hard-coded sample name on frontend #1516 --- .../analysis-areas-annotation-step.js | 2 +- .../sample-taking-sample-location-step.js | 10 +++++++--- arches_for_science/templates/javascript.htm | 2 ++ .../sample-taking-sample-location-step.htm | 6 +----- .../views/digital_resources_by_object_parts.py | 1 - 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js index 24d3287ab..924af6b9d 100644 --- a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js +++ b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js @@ -155,7 +155,7 @@ define([ this.areaNameFromTileData = (tileData) => { const nameValue = tileData[self.partIdentifierAssignmentLabelNodeId]; const baseName = self.getStrValue(nameValue) || ""; - return `${baseName} [${arches.translations.analysisArea} ${arches.translations.of} ${self.physicalThingName()}]`; + return arches.translations.analysisAreaOf.replace('{}', baseName).replace('{}', self.physicalThingName()); }; this.areaName = ko.computed(function(){ if (self.selectedAnalysisAreaInstance()){ diff --git a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.js b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.js index c5d285eb9..866d2b123 100644 --- a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.js +++ b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.js @@ -164,11 +164,15 @@ define([ } }); + this.sampleNameFromTileData = (data) => { + const partIdentifierAssignmentLabelNodeId = '3e541cc6-859b-11ea-97eb-acde48001122'; + const baseName = ko.unwrap(ko.unwrap(data[partIdentifierAssignmentLabelNodeId])?.[arches.activeLanguage]?.["value"]) || ""; + return arches.translations.sampleOf.replace('{}', baseName).replace('{}', params.physicalThingName); + }; + this.sampleName = ko.computed(function() { - var partIdentifierAssignmentLabelNodeId = '3e541cc6-859b-11ea-97eb-acde48001122'; if (self.selectedSampleLocationInstance()){ - const baseName = ko.unwrap(ko.unwrap(self.selectedSampleLocationInstance().data[partIdentifierAssignmentLabelNodeId])?.[arches.activeLanguage]?.["value"]) || ""; - return `${baseName} [Sample of ${params.physicalThingName}]`; + return self.sampleNameFromTileData(self.selectedSampleLocationInstance().data); } }); diff --git a/arches_for_science/templates/javascript.htm b/arches_for_science/templates/javascript.htm index 03bc7a388..729d012d5 100644 --- a/arches_for_science/templates/javascript.htm +++ b/arches_for_science/templates/javascript.htm @@ -150,6 +150,8 @@ analysis-area='{% trans "Analysis Area" as analysisArea %} "{{ analysisArea|escapejs }}"' analysis-areas='"{{ analysisAreas|pluralize }}"' no-modifying-areas='{% trans "Analysis Areas may not be modified in the sample taking workflow" as noModifyingAreas %} "{{ noModifyingAreas|escapejs }}"' + analysis-area-of='{% trans "{} [Analysis Area of {}]" as analysisAreaOf %} "{{ analysisAreaOf|escapejs }}"' + sample-of='{% trans "{} [Sample of {}]" as sampleOf %} "{{ sampleOf|escapejs }}"' sample-location='{% trans "Sample Location" as sampleLocation %} "{{ sampleLocation|escapejs }}"' no-modifying-samples='{% trans "Sample locations may not be modified in the analysis area workflow" as noModifyingSamples %} "{{ noModifyingSamples|escapejs }}"' physical-thing-placeholder='{% trans "find a physical thing: enter an artist, object name, artwork title or object number" as physicalThingPlaceholder %} "{{ physicalThingPlaceholder|escapejs }}"' diff --git a/arches_for_science/templates/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.htm b/arches_for_science/templates/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.htm index d60925fdd..50abb8c01 100644 --- a/arches_for_science/templates/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.htm +++ b/arches_for_science/templates/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.htm @@ -143,11 +143,7 @@
{% trans 'Sample locations' %}
- - + diff --git a/arches_for_science/views/digital_resources_by_object_parts.py b/arches_for_science/views/digital_resources_by_object_parts.py index 23ac4accf..bd9cd5cc4 100644 --- a/arches_for_science/views/digital_resources_by_object_parts.py +++ b/arches_for_science/views/digital_resources_by_object_parts.py @@ -51,7 +51,6 @@ def get_type(self, resourceid): try: object_type_tile = TileModel.objects.filter(resourceinstance_id=resourceid).get(nodegroup_id=type_nodegroup_id) object_types = object_type_tile.data[type_nodegroup_id] - # TODO(i18n) samples if sample_area_value_id in object_types: return "sample area" elif sample_value_id in object_types: From 9b81e96ca96d022a60656cb2e2c53538ea593929 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 12 Jan 2024 11:32:21 -0500 Subject: [PATCH 3/7] Standardize sampleOf and analysisAreaOf #1516 --- .../analysis-areas-annotation-step.js | 2 +- .../sample-taking-sample-location-step.js | 2 +- arches_for_science/templates/javascript.htm | 4 ++-- arches_for_science/views/analysis_area_and_sample_taking.py | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js index 924af6b9d..2708f0ca9 100644 --- a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js +++ b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js @@ -155,7 +155,7 @@ define([ this.areaNameFromTileData = (tileData) => { const nameValue = tileData[self.partIdentifierAssignmentLabelNodeId]; const baseName = self.getStrValue(nameValue) || ""; - return arches.translations.analysisAreaOf.replace('{}', baseName).replace('{}', self.physicalThingName()); + return arches.translations.analysisAreaOf.replace('{analysisName}', baseName).replace('{physicalThingName}', self.physicalThingName()); }; this.areaName = ko.computed(function(){ if (self.selectedAnalysisAreaInstance()){ diff --git a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.js b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.js index 866d2b123..c4320efdf 100644 --- a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.js +++ b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-sample-location-step.js @@ -167,7 +167,7 @@ define([ this.sampleNameFromTileData = (data) => { const partIdentifierAssignmentLabelNodeId = '3e541cc6-859b-11ea-97eb-acde48001122'; const baseName = ko.unwrap(ko.unwrap(data[partIdentifierAssignmentLabelNodeId])?.[arches.activeLanguage]?.["value"]) || ""; - return arches.translations.sampleOf.replace('{}', baseName).replace('{}', params.physicalThingName); + return arches.translations.sampleOf.replace('{sampleName}', baseName).replace('{physicalThingName}', params.physicalThingName); }; this.sampleName = ko.computed(function() { diff --git a/arches_for_science/templates/javascript.htm b/arches_for_science/templates/javascript.htm index 729d012d5..c6af2b236 100644 --- a/arches_for_science/templates/javascript.htm +++ b/arches_for_science/templates/javascript.htm @@ -149,9 +149,9 @@ takes-too-long='{% trans "This is taking longer than usual. Thank you for your patience." as takesTooLong %} "{{ takesTooLong|escapejs }}"' analysis-area='{% trans "Analysis Area" as analysisArea %} "{{ analysisArea|escapejs }}"' analysis-areas='"{{ analysisAreas|pluralize }}"' + analysis-area-of='{% trans "{analysisName} [Analysis Area of {physicalThingName}]" as analysisAreaOf %} "{{ analysisAreaOf|escapejs }}"' + sample-of='{% trans "{sampleName} [Sample of {physicalThingName}]" as sampleOf %} "{{ sampleOf|escapejs }}"' no-modifying-areas='{% trans "Analysis Areas may not be modified in the sample taking workflow" as noModifyingAreas %} "{{ noModifyingAreas|escapejs }}"' - analysis-area-of='{% trans "{} [Analysis Area of {}]" as analysisAreaOf %} "{{ analysisAreaOf|escapejs }}"' - sample-of='{% trans "{} [Sample of {}]" as sampleOf %} "{{ sampleOf|escapejs }}"' sample-location='{% trans "Sample Location" as sampleLocation %} "{{ sampleLocation|escapejs }}"' no-modifying-samples='{% trans "Sample locations may not be modified in the analysis area workflow" as noModifyingSamples %} "{{ noModifyingSamples|escapejs }}"' physical-thing-placeholder='{% trans "find a physical thing: enter an artist, object name, artwork title or object number" as physicalThingPlaceholder %} "{{ physicalThingPlaceholder|escapejs }}"' diff --git a/arches_for_science/views/analysis_area_and_sample_taking.py b/arches_for_science/views/analysis_area_and_sample_taking.py index 0a527569f..54e7ba902 100644 --- a/arches_for_science/views/analysis_area_and_sample_taking.py +++ b/arches_for_science/views/analysis_area_and_sample_taking.py @@ -188,7 +188,7 @@ def post(self, request): analysis_area_physical_thing_resourceid = part_identifier_assignment_tile_data[physical_part_of_object_nodeid][0]["resourceId"] base_name = part_identifier_assignment_tile_data[part_identifier_assignment_label_nodeid][get_language()]["value"] - name = _("{} [Analysis Area of {}]").format(base_name, parent_physical_thing_name) + name = _("{analysisName} [Analysis Area of {physicalThingName}]").format(analysisName=base_name, physicalThingName=parent_physical_thing_name) try: with transaction.atomic(): @@ -365,8 +365,8 @@ def post(self, request): sample_physical_thing_resourceid = sampling_unit_tile.data[sampling_area_sample_created_nodeid][0]["resourceId"] base_name = part_identifier_assignment_tile_data[part_identifier_assignment_label_nodeid][get_language()]["value"] - sample_name = _("{} [Sample of {}]").format(base_name, parent_physical_thing_name) - sample_area_name = _("{} [Sample Area of {}]").format(base_name, parent_physical_thing_name) + sample_name = _("{sampleName} [Sample of {physicalThingName}]").format(sampleName=base_name, physicalThingName=parent_physical_thing_name) + sample_area_name = _("{sampleName} [Sample Area of {physicalThingName}]").format(sampleName=base_name, physicalThingName=parent_physical_thing_name) try: with transaction.atomic(): From c7fb668effcfc4d752c06df3dca2008df12141b7 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 12 Jan 2024 11:54:18 -0500 Subject: [PATCH 4/7] Localize two more strings #1516 --- .../project-report-workflow/download-report.js | 1 - .../sample-taking-workflow/sampling-info-step.js | 3 +-- .../workflows/upload-dataset/instrument-info-step.js | 12 ++++++++---- arches_for_science/templates/javascript.htm | 2 ++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/arches_for_science/media/js/views/components/workflows/project-report-workflow/download-report.js b/arches_for_science/media/js/views/components/workflows/project-report-workflow/download-report.js index b52d25be7..1bbfe9722 100644 --- a/arches_for_science/media/js/views/components/workflows/project-report-workflow/download-report.js +++ b/arches_for_science/media/js/views/components/workflows/project-report-workflow/download-report.js @@ -86,7 +86,6 @@ define([ const reportDate = today.toLocaleDateString('en-US', options); const physicalThingsDetailsArray = [...Object.values(physicalThingsDetails)]; const objectOfStudyDetailsArray = physicalThingsDetailsArray.filter(thing => physicalThingFromPreviousStep.includes(thing.resourceinstanceid)); - // TODO(i18n) samples const analysisAreas = physicalThingsDetailsArray.filter(physicalThing => physicalThing.resource?.type?.["@display_value"] == 'analysis areas'); const annotationScreenshots = screenshots?.map((screenshot) => { const url = `${window.location.origin}/temp_file/${screenshot.fileId}`; diff --git a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sampling-info-step.js b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sampling-info-step.js index 33f1a7251..3e463d937 100644 --- a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sampling-info-step.js +++ b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sampling-info-step.js @@ -85,8 +85,7 @@ define([ }); this.samplingDate.subscribe(function(val){ - // TODO(i18n) samples - self.samplingName(["Sampling Activity of", self.physicalThingNameValue, val].join(' ')); + self.samplingName(arches.translations.samplingActivityOf.replace('{physicalThingName}', self.physicalThingNameValue) + ' ' + val); }); const selectPhysThingData = params.selectPhysThingData; diff --git a/arches_for_science/media/js/views/components/workflows/upload-dataset/instrument-info-step.js b/arches_for_science/media/js/views/components/workflows/upload-dataset/instrument-info-step.js index 7b2d3f779..978d09757 100644 --- a/arches_for_science/media/js/views/components/workflows/upload-dataset/instrument-info-step.js +++ b/arches_for_science/media/js/views/components/workflows/upload-dataset/instrument-info-step.js @@ -107,8 +107,10 @@ define([ self.instrumentInstance(self.createRelatedInstance(val, instrumentUsedInObservation, observationInstrumentUsedIn)); instrumentData.then(function(data){ self.instrumentName(data._source.displayname); - // TODO(i18n) samples - self.nameValue(`Observation of ${physThingName} with ${data._source.displayname} ${self.dateValue()}`); + const formattedName = arches.translations.observationWith + .replace('{physicalThingName}', physThingName) + .replace('{instrumentName}', data._source.displayname); + self.nameValue(`${formattedName} ${self.dateValue()}`); }); } if (!val) { @@ -119,8 +121,10 @@ define([ this.dateValue.subscribe(function(val){ if (self.instrumentName()) { - // TODO(i18n) samples - self.nameValue(`Observation of ${physThingName} with ${self.instrumentName()} ${val}`); + const formattedName = arches.translations.observationWith + .replace('{physicalThingName}', physThingName) + .replace('{instrumentName}', self.instrumentName()); + self.nameValue(`${formattedName} ${val}`); } }); diff --git a/arches_for_science/templates/javascript.htm b/arches_for_science/templates/javascript.htm index c6af2b236..641d76a4b 100644 --- a/arches_for_science/templates/javascript.htm +++ b/arches_for_science/templates/javascript.htm @@ -151,6 +151,7 @@ analysis-areas='"{{ analysisAreas|pluralize }}"' analysis-area-of='{% trans "{analysisName} [Analysis Area of {physicalThingName}]" as analysisAreaOf %} "{{ analysisAreaOf|escapejs }}"' sample-of='{% trans "{sampleName} [Sample of {physicalThingName}]" as sampleOf %} "{{ sampleOf|escapejs }}"' + sampling-activity-of='{% trans "Sampling Activity of {physicalThingName}" as samplingActivityOf %} "{{ samplingActivityOf|escapejs }}"' no-modifying-areas='{% trans "Analysis Areas may not be modified in the sample taking workflow" as noModifyingAreas %} "{{ noModifyingAreas|escapejs }}"' sample-location='{% trans "Sample Location" as sampleLocation %} "{{ sampleLocation|escapejs }}"' no-modifying-samples='{% trans "Sample locations may not be modified in the analysis area workflow" as noModifyingSamples %} "{{ noModifyingSamples|escapejs }}"' @@ -158,6 +159,7 @@ annotation-summary-for='{% trans "Annotation Summary for" as annotationSummaryFor %} "{{ annotationSummaryFor|escapejs }}"' existing-annotation='{% trans "{title} is a {type} of {parent},\n which is created before" as existingAnnotation %} "{{ existingAnnotation|escapejs }}"' timespan='{% trans "TimeSpan" as timespan %} "{{ timespan|escapejs }}"' + observation-with='{% trans "Observation of {physicalThingName} with {instrumentName}" as observationWith %} "{{ observationWith|escapejs }}"' > {% endblock arches_translations %} From 78a7339d898612bfa31799aa2458465e79c19ead Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 12 Jan 2024 17:10:25 -0500 Subject: [PATCH 5/7] Remove more hardcoded sample logic #1516 TODO: test report workflow annotations --- .../js/views/components/annotation-summary.js | 16 +++-- .../analysis-areas-annotation-step.js | 1 + .../analysis-areas-final-step.js | 24 +++++-- .../add-annotations.js | 16 +++-- .../sample-taking-final-step.js | 64 +++++++++++-------- arches_for_science/templates/javascript.htm | 2 +- 6 files changed, 74 insertions(+), 49 deletions(-) diff --git a/arches_for_science/media/js/views/components/annotation-summary.js b/arches_for_science/media/js/views/components/annotation-summary.js index 014306518..cf9101e69 100644 --- a/arches_for_science/media/js/views/components/annotation-summary.js +++ b/arches_for_science/media/js/views/components/annotation-summary.js @@ -69,6 +69,12 @@ define([ return feature.properties; }, onEachFeature: function(feature, layer) { + const classificationConcepts = Object.freeze({ + // Concept IDs, not values + "a2588fa8-5ae6-4770-a473-dec0c05fb175": 'Analysis Area', + "2703e524-b5ea-4548-bea7-7ce354e4e05a": 'Sample Area', + "9db724b9-b3c7-4761-9a50-673d64a15bd8": 'Sample', + }); if (feature.properties.active === false){ var popup = L.popup({ closeButton: false, @@ -76,15 +82,11 @@ define([ }) .setContent(popupHtml) .on('add', function() { + // hope that translator has not adjusted the location of the bracket. const titleArray = feature.properties.name.split('['); const title = titleArray[0].trim(); - // TODO(i18n) samples - const type = titleArray[1].startsWith('Analysis Area') ? 'Analysis Area': - titleArray[1].startsWith('Sample Area') ? 'Sample Area': - 'Part'; - const parent = titleArray[1].startsWith('Analysis Area') ? titleArray[1].replace('Analysis Area of ', '').replace(']',''): - titleArray[1].startsWith('Sample Area') ? titleArray[1].replace('Sample Area of ','').replace(']',''): - titleArray[1].replace(']',''); + const type = classificationConcepts[feature.properties.classificationConceptId]; + const parent = feature.properties.parentPhysicalThingName; const description = ( arches.translations.existingAnnotation .replace('{title}', title) diff --git a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js index 2708f0ca9..9fa3457a8 100644 --- a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js +++ b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-annotation-step.js @@ -811,6 +811,7 @@ define([ }) .then(function(json) { json.features.forEach(function(feature) { + // TODO(i18n) slug or name? feature.properties.graphName = "Physical Thing"; if (self.sampleLocationTileIds.includes(feature.properties.tileId)) { feature.properties.type = 'sample_location'; diff --git a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-final-step.js b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-final-step.js index e11fc2c11..10bf24260 100644 --- a/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-final-step.js +++ b/arches_for_science/media/js/views/components/workflows/analysis-areas-workflow/analysis-areas-final-step.js @@ -5,8 +5,9 @@ define([ 'arches', 'views/components/workflows/summary-step', 'templates/views/components/workflows/analysis-areas-workflow/analysis-areas-final-step.htm', + 'utils/label-based-graph-utils', 'views/components/annotation-summary', -], function(ko, _, uuid, arches, SummaryStep, analysisAreasFinalStepTemplate) { +], function(ko, _, uuid, arches, SummaryStep, analysisAreasFinalStepTemplate, labelBasedGraphUtils) { function viewModel(params) { var self = this; @@ -97,12 +98,21 @@ define([ annotator: annotation.annotator, }); } else { - annotation.annotationJson.features.map(feature => { - feature.properties.color = '#999999'; - feature.properties.fillColor = '#999999'; - feature.properties.tileId = annotation.tileId; - feature.properties.name = annotation.annotationName; - feature.properties.active = false; + // TODO: fetch in parallel + fetch(self.urls.api_resources(annotation.resourceId) + '?format=json&compact=false&v=beta') + .then(response => response.json()) + .then(data => { + annotation.annotationJson.features.map(feature => { + feature.properties.color = '#999999'; + feature.properties.fillColor = '#999999'; + feature.properties.tileId = annotation.tileId; + feature.properties.name = annotation.annotationName; + feature.properties.active = false; + feature.properties.classificationConceptId = data.resource.type.concept_details[0].concept_id; + feature.properties.parentPhysicalThingName = labelBasedGraphUtils.getPropByNodeId( + data.resource, 'f8d5fe4c-b31d-11e9-9625-a4d18cec433a', '@display_value' + ); + }); }); } }); diff --git a/arches_for_science/media/js/views/components/workflows/project-report-workflow/add-annotations.js b/arches_for_science/media/js/views/components/workflows/project-report-workflow/add-annotations.js index 4b469b8da..c2b2fa972 100644 --- a/arches_for_science/media/js/views/components/workflows/project-report-workflow/add-annotations.js +++ b/arches_for_science/media/js/views/components/workflows/project-report-workflow/add-annotations.js @@ -225,15 +225,17 @@ define([ }) .setContent(popupHtml) .on('add', function() { + const classificationConcepts = Object.freeze({ + // Concept IDs, not values + "a2588fa8-5ae6-4770-a473-dec0c05fb175": 'Analysis Area', + "2703e524-b5ea-4548-bea7-7ce354e4e05a": 'Sample Area', + "9db724b9-b3c7-4761-9a50-673d64a15bd8": 'Sample', + }); + // hope that translator has not adjusted the location of the bracket. const titleArray = feature.properties.name.split('['); const title = titleArray[0].trim(); - // TODO(i18n) samples - const type = titleArray[1].startsWith('Analysis Area') ? 'Analysis Area': - titleArray[1].startsWith('Sample Area') ? 'Sample Area': - 'Part'; - const parent = titleArray[1].startsWith('Analysis Area') ? titleArray[1].replace('Analysis Area of ', '').replace(']',''): - titleArray[1].startsWith('Sample Area') ? titleArray[1].replace('Sample Area of ','').replace(']',''): - titleArray[1].replace(']',''); + const type = classificationConcepts[feature.properties.classificationConceptId]; + const parent = feature.properties.parentPhysicalThingName; const description = ( arches.translations.existingAnnotation .replace('{title}', title) diff --git a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-final-step.js b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-final-step.js index b574773ff..23410a0be 100644 --- a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-final-step.js +++ b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-final-step.js @@ -56,6 +56,12 @@ define([ return feature.properties; }, onEachFeature: function(feature, layer) { + const classificationConcepts = Object.freeze({ + // Concept IDs, not values + "a2588fa8-5ae6-4770-a473-dec0c05fb175": 'Analysis Area', + "2703e524-b5ea-4548-bea7-7ce354e4e05a": 'Sample Area', + "9db724b9-b3c7-4761-9a50-673d64a15bd8": 'Sample', + }); if (!feature.properties.active){ var popup = L.popup({ closeButton: false, @@ -63,15 +69,11 @@ define([ }) .setContent(iiifPopup) .on('add', function() { + // hope that translator has not adjusted the location of the bracket. const titleArray = feature.properties.locationName.split('['); const title = titleArray[0].trim(); - // TODO(i18n) samples - const type = titleArray[1].startsWith('Analysis Area') ? 'Analysis Area': - titleArray[1].startsWith('Sample Area') ? 'Sample Area': - 'Part'; - const parent = titleArray[1].startsWith('Analysis Area') ? titleArray[1].replace('Analysis Area of ', '').replace(']',''): - titleArray[1].startsWith('Sample Area') ? titleArray[1].replace('Sample Area of ','').replace(']',''): - titleArray[1].replace(']',''); + const type = classificationConcepts[feature.properties.classificationConceptId]; + const parent = feature.properties.parentPhysicalThingName; const description = ( arches.translations.existingAnnotation .replace('{title}', title) @@ -209,35 +211,43 @@ define([ const parentPhyiscalThingResourceId = self.getResourceValue(val.resource["Sampling Unit"][0], ['Sampling Area','Overall Object Sampled','resourceId']); const parentPhyiscalThing = ko.observable(); self.getResourceData(parentPhyiscalThingResourceId, parentPhyiscalThing); - parentPhyiscalThing.subscribe(function(val){ // 2nd request + parentPhyiscalThing.subscribe(async function(val) { // 2nd request const parts = self.getResourceValue(val.resource, ['Part Identifier Assignment']); - parts.forEach(function(part){ + for (const part of parts) { const locationName = self.getResourceValue(part,['Part Identifier Assignment_Physical Part of Object','@display_value']); const tileId = self.getResourceValue(part,['@tile_id']); - const sampleAreaResourceId = self.getResourceValue(part,['Part Identifier Assignment_Physical Part of Object','resourceId']); + const partResourceId = self.getResourceValue(part,['Part Identifier Assignment_Physical Part of Object','resourceId']); const partsAnnotationString = self.getResourceValue(part,['Part Identifier Assignment_Polygon Identifier','@display_value']); if (partsAnnotationString) { const locationAnnotation = JSON.parse(partsAnnotationString.replaceAll("'",'"')); const canvas = locationAnnotation.features[0].properties.canvas; - locationAnnotation.features.forEach(function(feature){ - feature.properties.active = false; - feature.properties.tileId = tileId; - feature.properties.locationName = locationName; - feature.properties.sampleAreaResourceId = sampleAreaResourceId; - }); - if (canvas in partsAnnotationCollection) { - partsAnnotationCollection[canvas].push({ - locationAnnotation: locationAnnotation, - sampleAreaResourceId: sampleAreaResourceId, + // TODO: fetch in parallel + await fetch(self.urls.api_resources(partResourceId) + '?format=json&compact=false&v=beta') + .then(response => response.json()) + .then(data => { + locationAnnotation.features.forEach(function(feature) { + feature.properties.active = false; + feature.properties.tileId = tileId; + feature.properties.locationName = locationName; + // misnomer, could be analysis area + feature.properties.sampleAreaResourceId = partResourceId; + feature.properties.classificationConceptId = data.resource.type.concept_details[0].concept_id; + feature.properties.parentPhysicalThingName = parentPhyiscalThing().resource._label['@display_value']; }); - } else { - partsAnnotationCollection[canvas] = [{ - locationAnnotation: locationAnnotation, - sampleAreaResourceId: sampleAreaResourceId, - }]; - } + if (canvas in partsAnnotationCollection) { + partsAnnotationCollection[canvas].push({ + locationAnnotation: locationAnnotation, + sampleAreaResourceId: partResourceId, + }); + } else { + partsAnnotationCollection[canvas] = [{ + locationAnnotation: locationAnnotation, + sampleAreaResourceId: partResourceId, + }]; + } + }); } - }); + } // add the annotation of parts to the final object self.annotationStatus = ko.observable(); diff --git a/arches_for_science/templates/javascript.htm b/arches_for_science/templates/javascript.htm index 641d76a4b..26152677d 100644 --- a/arches_for_science/templates/javascript.htm +++ b/arches_for_science/templates/javascript.htm @@ -157,7 +157,7 @@ no-modifying-samples='{% trans "Sample locations may not be modified in the analysis area workflow" as noModifyingSamples %} "{{ noModifyingSamples|escapejs }}"' physical-thing-placeholder='{% trans "find a physical thing: enter an artist, object name, artwork title or object number" as physicalThingPlaceholder %} "{{ physicalThingPlaceholder|escapejs }}"' annotation-summary-for='{% trans "Annotation Summary for" as annotationSummaryFor %} "{{ annotationSummaryFor|escapejs }}"' - existing-annotation='{% trans "{title} is a {type} of {parent},\n which is created before" as existingAnnotation %} "{{ existingAnnotation|escapejs }}"' + existing-annotation='{% trans "{title} is a(n) {type} of {parent}, which is created before" as existingAnnotation %} "{{ existingAnnotation|escapejs }}"' timespan='{% trans "TimeSpan" as timespan %} "{{ timespan|escapejs }}"' observation-with='{% trans "Observation of {physicalThingName} with {instrumentName}" as observationWith %} "{{ observationWith|escapejs }}"' > From a5e8865ab0703b686434eebe4f2732653c1a6dac Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 12 Jan 2024 18:10:08 -0500 Subject: [PATCH 6/7] Remove hardcoded sample substrings #1516 --- .../workflows/create-project-workflow/add-things-step.js | 7 ++----- arches_for_science/templates/javascript.htm | 1 + 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arches_for_science/media/js/views/components/workflows/create-project-workflow/add-things-step.js b/arches_for_science/media/js/views/components/workflows/create-project-workflow/add-things-step.js index 4b48458f8..e1080a6a4 100644 --- a/arches_for_science/media/js/views/components/workflows/create-project-workflow/add-things-step.js +++ b/arches_for_science/media/js/views/components/workflows/create-project-workflow/add-things-step.js @@ -94,9 +94,6 @@ define([ analysis: '31d97bdd-f10f-4a26-958c-69cb5ab69af1', }; this.physicalThingTypeNodeId = '8ddfe3ab-b31d-11e9-aff0-a4d18cec433a'; - // TODO(i18n) samples - const sampleSubstring = '[Sample'; // for "[Sample of ..." and "[Sample Area of ..." - const regionSubstring = '[Region'; this.value.subscribe(function(a) { a.forEach(function(action) { @@ -332,8 +329,8 @@ define([ return ( result.context_label.includes("Physical Thing") || result.context_label.includes("Search Term") - ) && (self.includeSamples() || !result.text.includes(sampleSubstring)) - && (self.includeAnalysisAreas() || !result.text.includes(regionSubstring)) + ) && (self.includeSamples() || !result.text.includes(arches.translations.sample)) + && (self.includeAnalysisAreas() || !result.text.includes(arches.translations.analysisArea)) }); return { "results": filteredResults diff --git a/arches_for_science/templates/javascript.htm b/arches_for_science/templates/javascript.htm index 26152677d..9ec683526 100644 --- a/arches_for_science/templates/javascript.htm +++ b/arches_for_science/templates/javascript.htm @@ -150,6 +150,7 @@ analysis-area='{% trans "Analysis Area" as analysisArea %} "{{ analysisArea|escapejs }}"' analysis-areas='"{{ analysisAreas|pluralize }}"' analysis-area-of='{% trans "{analysisName} [Analysis Area of {physicalThingName}]" as analysisAreaOf %} "{{ analysisAreaOf|escapejs }}"' + sample='{% trans "Sample" as sample %} "{{ sample|escapejs }}"' sample-of='{% trans "{sampleName} [Sample of {physicalThingName}]" as sampleOf %} "{{ sampleOf|escapejs }}"' sampling-activity-of='{% trans "Sampling Activity of {physicalThingName}" as samplingActivityOf %} "{{ samplingActivityOf|escapejs }}"' no-modifying-areas='{% trans "Analysis Areas may not be modified in the sample taking workflow" as noModifyingAreas %} "{{ noModifyingAreas|escapejs }}"' From 4046d16242d3c6f76bc3765ae25a26f9b1a346ed Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Mon, 15 Jan 2024 09:59:19 -0500 Subject: [PATCH 7/7] Add handling for no label re #1516 --- .../sample-taking-workflow/sample-taking-final-step.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-final-step.js b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-final-step.js index 23410a0be..010687f04 100644 --- a/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-final-step.js +++ b/arches_for_science/media/js/views/components/workflows/sample-taking-workflow/sample-taking-final-step.js @@ -232,7 +232,7 @@ define([ // misnomer, could be analysis area feature.properties.sampleAreaResourceId = partResourceId; feature.properties.classificationConceptId = data.resource.type.concept_details[0].concept_id; - feature.properties.parentPhysicalThingName = parentPhyiscalThing().resource._label['@display_value']; + feature.properties.parentPhysicalThingName = parentPhyiscalThing().resource._label?.['@display_value'] ?? ''; }); if (canvas in partsAnnotationCollection) { partsAnnotationCollection[canvas].push({