From 9021773604a0dd9afc485035b28e80385ac525b4 Mon Sep 17 00:00:00 2001 From: Ryan Anderson Date: Wed, 10 May 2023 10:34:05 -0700 Subject: [PATCH 001/342] stub out chemical analysis image workflow, re #1134 --- .../add-chemical-analysis-images-workflow.js | 132 +++++++ ...add-chemical-analysis-images-final-step.js | 129 +++++++ ...add-chemical-analysis-images-image-step.js | 356 ++++++++++++++++++ .../workflows/select-observation-step.js | 183 +++++++++ ...add-chemical-analysis-images-workflow.json | 10 + afs/plugins/init-workflow.json | 9 + .../add-chemical-analysis-images-workflow.htm | 2 + ...dd-chemical-analysis-images-final-step.htm | 61 +++ ...dd-chemical-analysis-images-image-step.htm | 79 ++++ .../workflows/select-observation-step.htm | 56 +++ 10 files changed, 1017 insertions(+) create mode 100644 afs/media/js/views/components/plugins/add-chemical-analysis-images-workflow.js create mode 100644 afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.js create mode 100644 afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.js create mode 100644 afs/media/js/views/components/workflows/select-observation-step.js create mode 100644 afs/plugins/add-chemical-analysis-images-workflow.json create mode 100644 afs/templates/views/components/plugins/add-chemical-analysis-images-workflow.htm create mode 100644 afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.htm create mode 100644 afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.htm create mode 100644 afs/templates/views/components/workflows/select-observation-step.htm diff --git a/afs/media/js/views/components/plugins/add-chemical-analysis-images-workflow.js b/afs/media/js/views/components/plugins/add-chemical-analysis-images-workflow.js new file mode 100644 index 000000000..dfc11b1a4 --- /dev/null +++ b/afs/media/js/views/components/plugins/add-chemical-analysis-images-workflow.js @@ -0,0 +1,132 @@ +define([ + 'knockout', + 'jquery', + 'arches', + 'viewmodels/workflow', + 'viewmodels/alert', + 'templates/views/components/plugins/add-chemical-analysis-images-workflow.htm', + 'viewmodels/workflow-step', + 'views/components/workflows/select-observation-step', + 'views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step', + 'views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step', +], function(ko, $, arches, Workflow, AlertViewModel, analysisAreasWorkflowTemplate) { + return ko.components.register('add-chemical-analysis-images-workflow', { + viewModel: function(params) { + this.componentName = 'add-chemical-analysis-images-workflow'; + + this.stepConfig = [ + { + title: 'Project Info', + name: 'select-project', /* unique to workflow */ + required: true, + informationboxdata: { + heading: 'Workflow Goal: Record Locations and Regions of Interest', + text: ` + Regions of interest are the areas on a physical object (whole object or sample) in which a measurement -- whether non-invasive or minimally invasive -- was performed. + To be meaningful, you need to describe the location or region of a physical object that is being described/measured. + This workflow will guide you through the steps to document the location of your regions of interest. + `, + }, + layoutSections: [ + { + componentConfigs: [ + { + componentName: 'select-observation-step', + uniqueInstanceName: 'select-observation', /* unique to step */ + parameters: { + graphids: [ + '615b11ee-c457-11e9-910c-a4d18cec433a', /* Observation */ + '0b9235d9-ca85-11e9-9fa2-a4d18cec433a'/* Project */ + ], + }, + }, + ], + }, + ], + }, + { + title: 'Image', + name: 'image-step', /* unique to workflow */ + required: true, + informationboxdata: { + heading: 'Image Services', + text: ` + Image Services provide you with picture(s) of an object, often from multiple vantage points, that can be annotated to indicate the location or region of an observation. + If you wish, you can upload photographs and automatically create a new image service to document the location of your observations of an object. + `, + }, + lockableExternalSteps: ['select-project'], + layoutSections: [ + { + sectionTitle: 'Image Service', + componentConfigs: [ + { + componentName: 'add-chemical-analysis-images-image-step', + uniqueInstanceName: 'image-service-instance', /* unique to step */ + tilesManaged: 'one', + parameters: { + graphid: '707cbd78-ca7a-11e9-990b-a4d18cec433a', /* Digital Resources */ + physicalThingResourceId: "['select-project']['select-phys-thing']['physicalThing']" + }, + }, + ], + }, + ], + }, + { + title: 'Summary', + name: 'add-chemical-analysis-images-complete', /* unique to workflow */ + description: 'Summary', + layoutSections: [ + { + componentConfigs: [ + { + componentName: 'add-chemical-analysis-images-final-step', + uniqueInstanceName: 'add-chemical-analysis-images-final', + tilesManaged: 'none', + parameters: { + sampleObjectResourceId: "['select-project']['select-phys-thing']['physicalThing']", + relatedProjectData: "['select-project']['select-phys-thing']", + imageStepData: "['image-step']['image-service-instance'][0]['data']", + digitalReferenceResourceId: "['image-step']['image-service-instance'][0]['resourceinstance_id']" + }, + }, + ], + }, + ], + } + ]; + + Workflow.apply(this, [params]); + + this.reverseWorkflowTransactions = function() { + const quitUrl = this.quitUrl; + return $.ajax({ + type: "POST", + url: arches.urls.transaction_reverse(this.id()) + }).then(function() { + params.loading(false); + window.location.href = quitUrl; + }); + }; + + this.quitWorkflow = function(){ + this.alert( + new AlertViewModel( + 'ep-alert-red', + 'Are you sure you would like to delete this workflow?', + 'All data created during the course of this workflow will be deleted.', + function(){}, //does nothing when canceled + () => { + params.loading('Cleaning up...'); + this.reverseWorkflowTransactions(); + }, + ) + ); + }; + + this.quitUrl = arches.urls.plugin('init-workflow'); + }, + template: analysisAreasWorkflowTemplate + }); +}); diff --git a/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.js b/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.js new file mode 100644 index 000000000..ec69d4a5e --- /dev/null +++ b/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.js @@ -0,0 +1,129 @@ +define([ + 'knockout', + 'underscore', + 'uuid', + 'arches', + 'views/components/workflows/summary-step', + 'templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.htm', + 'views/components/annotation-summary', +], function(ko, _, uuid, arches, SummaryStep, addChemicalAnalysisImagesFinalStepTemplate) { + + function viewModel(params) { + var self = this; + + params.form.resourceId(params.sampleObjectResourceId); + const digitalResourceServiceIdentifierContentNodeId = '56f8e9bd-ca7c-11e9-b578-a4d18cec433a'; + const manifestUrl = params.imageStepData[digitalResourceServiceIdentifierContentNodeId][arches.activeLanguage]['value']; + const digitalReferenceResourceId = params.digitalReferenceResourceId; + + this.regionInstances = params.regionsStepData?.data.map(function(data){ + return { + regionName: data.data["3e541cc6-859b-11ea-97eb-acde48001122"], + regionResource: data.data["b240c366-8594-11ea-97eb-acde48001122"][0]["resourceId"], + }; + }); + const currentAnalysisAreas = params.regionsStepData?.currentAnalysisAreas; + + SummaryStep.apply(this, [params]); + + this.objectAnnotations = ko.observableArray(); + this.resourceData.subscribe(function(val){ + this.displayName = val['displayname'] || 'unnamed'; + const digitalReference = val.resource['Digital Reference'].find(function(val){ + return val['Digital Source']['resourceId'] === digitalReferenceResourceId; + }); + this.reportVals = { + projectName: {'name': 'Project', 'value': params.relatedProjectData.projectName, 'resourceid': params.relatedProjectData.project}, + parentObject: {'name': 'Object', 'value': this.getResourceValue(val.resource, ['part of', '@display_value'])}, + digitalReference: {'name': 'Image Service', 'value': digitalReference['Digital Source']["@display_value"]}, + }; + var annotationCollection = {}; + self.regionResourceIds = self.regionInstances?.map(x => x.regionResource); + val.resource['Part Identifier Assignment'].forEach(function(annotation){ + const annotationResourceId = self.getResourceValue(annotation,['Part Identifier Assignment_Physical Part of Object','resourceId']); + const annotationName = self.getResourceValue(annotation,['Part Identifier Assignment_Physical Part of Object','@display_value']); + const annotationLabel = self.getResourceValue(annotation,['Part Identifier Assignment_Label','@display_value']); + const annotator = self.getResourceValue(annotation,['Part Identifier Assignment_Annotator','@display_value']); + const annotationStr = self.getResourceValue(annotation,['Part Identifier Assignment_Polygon Identifier','@display_value']); + const tileId = self.getResourceValue(annotation,['Part Identifier Assignment_Polygon Identifier','@tile_id']); + if (annotationStr) { + const annotationJson = JSON.parse(annotationStr.replaceAll("'",'"')); + if (annotationJson.features.length > 0){ + const currentManifestUrl = annotation['Part Identifier Assignment_Polygon Identifier']['geojson']['features'][0]['properties']['manifest']; + if (currentManifestUrl === manifestUrl){ + const canvas = annotationJson.features[0].properties.canvas; + annotationJson.features.forEach(function(feature){ + feature.properties.tileId = tileId; + }); + if (canvas in annotationCollection) { + annotationCollection[canvas].push({ + resourceId: annotationResourceId, + tileId: tileId, + annotationName: annotationName, + annotationLabel: annotationLabel, + annotator: annotator, + annotationJson: annotationJson, + }); + } else { + annotationCollection[canvas] = [{ + resourceId: annotationResourceId, + tileId: tileId, + annotationName: annotationName, + annotationLabel: annotationLabel, + annotator: annotator, + annotationJson: annotationJson, + }]; + } + } + } + } + }); + + for (const canvas in annotationCollection) { + let name; + let annotationCombined; + let info = []; + annotationCollection[canvas].forEach(function(annotation){ + name = annotation.annotationName; + if (annotationCombined) { + annotationCombined.features = annotationCombined.features.concat(annotation.annotationJson.features); + } else { + annotationCombined = annotation.annotationJson; + } + if (currentAnalysisAreas?.includes(annotation.tileId)) { + info.push({ + tileId: annotation.tileId, + name: annotation.annotationName, + 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; + }); + } + }); + + const leafletConfig = self.prepareAnnotation(annotationCombined); + if (info.length > 0) { + self.objectAnnotations.push({ + name: name, + info: info, + leafletConfig: leafletConfig, + featureCollection: annotationCombined, + }); + } + } + this.loading(false); + }, this); + } + + ko.components.register('add-chemical-analysis-images-final-step', { + viewModel: viewModel, + template: addChemicalAnalysisImagesFinalStepTemplate + }); + return viewModel; +}); diff --git a/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.js b/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.js new file mode 100644 index 000000000..a0d4fb871 --- /dev/null +++ b/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.js @@ -0,0 +1,356 @@ +define([ + 'underscore', + 'jquery', + 'arches', + 'knockout', + 'knockout-mapping', + 'models/graph', + 'viewmodels/card', + 'templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.htm', + 'views/components/plugins/manifest-manager', +], function(_, $, arches, ko, koMapping, GraphModel, CardViewModel, addChemicalAnalysisImagesImageStepTemplate) { + function viewModel(params) { + var self = this; + params.pageVm.loading(true); + + this.workflowId = params.form.workflowId; + + this.isManifestManagerHidden = ko.observable(true); + this.shouldShowEditService = ko.observable(true); + + this.selectedPhysicalThingImageServiceName = ko.observable(); + this.selectedPhysicalThingImageServiceName.subscribe(function(imageServiceName) { + params.dirty(true); + + if (imageServiceName) { + var resourceData = self.getResourceDataAssociatedWithPreviouslyPersistedTile(imageServiceName); + if (resourceData) { params.dirty(false); } + } + }); + + this.physicalThingResourceId = koMapping.toJS(params.physicalThingResourceId); + + this.physicalThingDigitalReferenceCard = ko.observable(); + this.physicalThingDigitalReferenceCard.subscribe(function(card) { + self.getPhysicalThingRelatedDigitalReferenceData(card); + }); + + this.physicalThingDigitalReferenceTile = ko.observable(); + + this.physicalThingDigitalReferencePreferredManifestResourceData = ko.observableArray(); + this.physicalThingDigitalReferenceAlternateManifestResourceData = ko.observableArray(); + + var digitalResourceNameNodegroupId = 'd2fdae3d-ca7a-11e9-ad84-a4d18cec433a'; + var digitalResourceNameCard = params.form.topCards.find(function(topCard) { + return topCard.nodegroupid === digitalResourceNameNodegroupId; + }); + this.digitalResourceNameTile = digitalResourceNameCard.getNewTile(); + this.locked = params.form.locked; + + var digitalResourceStatementNodegroupId = 'da1fac57-ca7a-11e9-86a3-a4d18cec433a'; + var digitalResourceStatementCard = params.form.topCards.find(function(topCard) { + return topCard.nodegroupid === digitalResourceStatementNodegroupId; + }); + this.digitalResourceStatementTile = digitalResourceStatementCard.getNewTile(); + + + var digitalResourceServiceNodegroupId = '29c8c76e-ca7c-11e9-9e11-a4d18cec433a'; + var digitalResourceServiceCard = params.form.topCards.find(function(topCard) { + return topCard.nodegroupid === digitalResourceServiceNodegroupId; + }); + this.digitalResourceServiceTile = digitalResourceServiceCard.getNewTile(); + + const digitalResourceTypeNodegroupId = '09c1778a-ca7b-11e9-860b-a4d18cec433a'; + const digitalResourceTypeCard = params.form.topCards.find(function(topCard) { + return topCard.nodegroupid === digitalResourceTypeNodegroupId; + }); + this.digitalResourceTypeTile = digitalResourceTypeCard.getNewTile(); + + var digitalResourceServiceIdentifierNodegroupId = '56f8e26e-ca7c-11e9-9aa3-a4d18cec433a'; + var digitalResourceServiceIdentifierCard = digitalResourceServiceCard.cards().find(function(topCard) { + return topCard.nodegroupid === digitalResourceServiceIdentifierNodegroupId; + }); + this.digitalResourceServiceIdentifierTile = digitalResourceServiceIdentifierCard.getNewTile(); + + const digitalResourceNameContentNodeId = 'd2fdc2fa-ca7a-11e9-8ffb-a4d18cec433a'; + const digitalResourceStatementContentNodeId = 'da1fbca1-ca7a-11e9-8256-a4d18cec433a'; + const digitalResourceServiceTypeConformanceNodeId = 'cec360bd-ca7f-11e9-9ab7-a4d18cec433a'; + const digitalResourceServiceIdentifierContentNodeId = '56f8e9bd-ca7c-11e9-b578-a4d18cec433a'; + const digitalResourceServiceIdentifierTypeNodeId = '56f8e759-ca7c-11e9-bda1-a4d18cec433a'; + const digitalResourceServiceTypeNodeId= '5ceedd21-ca7c-11e9-a60f-a4d18cec433a'; + const digitalResourceTypeNodeId = '09c1778a-ca7b-11e9-860b-a4d18cec433a'; + + this.buildStrObject = str => { + return {[arches.activeLanguage]: { + "value": str, + "direction": arches.languages.find(lang => lang.code == arches.activeLanguage).default_direction + }}; + }; + + + this.manifestData = ko.observable(); + this.manifestData.subscribe(function(manifestData) { + if (manifestData) { + self.digitalResourceNameTile.data[digitalResourceNameContentNodeId](self.buildStrObject(manifestData.label)); + const manifestDescription = Array.isArray(manifestData.description) ? self.buildStrObject(manifestData.description[0]) : self.buildStrObject(manifestData.description); + self.digitalResourceStatementTile.data[digitalResourceStatementContentNodeId](manifestDescription); + self.digitalResourceServiceIdentifierTile.data[digitalResourceServiceIdentifierContentNodeId](self.buildStrObject(manifestData['@id'])); + self.digitalResourceServiceIdentifierTile.data[digitalResourceServiceIdentifierTypeNodeId](["f32d0944-4229-4792-a33c-aadc2b181dc7"]); // uniform resource locators concept value id + self.digitalResourceServiceTile.data[digitalResourceServiceTypeConformanceNodeId](self.buildStrObject(manifestData['@context'])); + } + else { + self.digitalResourceNameTile.data[digitalResourceNameContentNodeId](null); + self.digitalResourceStatementTile.data[digitalResourceStatementContentNodeId](null); + self.digitalResourceServiceIdentifierTile.data[digitalResourceServiceIdentifierContentNodeId](null); + self.digitalResourceServiceIdentifierTile.data[digitalResourceServiceIdentifierTypeNodeId](null); + self.digitalResourceServiceTile.data[digitalResourceServiceTypeConformanceNodeId](null); + } + }); + + + this.initialize = function() { + params.form.save = self.save; + params.form.reset = self.reset; + + if (!self.physicalThingDigitalReferenceCard() || !self.physicalThingDigitalReferenceTile()) { + self.getPhysicalThingDigitalReferenceData(); + } + }; + + this.getResourceDataAssociatedWithPreviouslyPersistedTile = function(imageServiceName) { + var preferredManifestResourceData = self.physicalThingDigitalReferencePreferredManifestResourceData().find(function(manifestData) { return manifestData.displayname === imageServiceName; }); + var alternateManifestResourceData = self.physicalThingDigitalReferenceAlternateManifestResourceData().find(function(manifestData) { return manifestData.displayname === imageServiceName; }); + + var manifestResourceData = preferredManifestResourceData || alternateManifestResourceData; /* the same displayname should not exist in both values */ + + /* will not have tiles if creating a new manifest */ + if (manifestResourceData && manifestResourceData.tiles && params.form.savedData()) { + var previouslyPersistedTileId = params.form.savedData().tileid; + + var tileMatchingPreviouslyPersistedTile = manifestResourceData.tiles.find(function(tile) { + return tile.tileid === previouslyPersistedTileId; + }); + + if (tileMatchingPreviouslyPersistedTile && manifestResourceData.displayname === imageServiceName) { + return manifestResourceData; + } + } + }; + + this.save = function() { + params.form.complete(false); + params.form.saving(true); + + params.form.lockExternalStep("select-project", true); + if (self.manifestData() && self.manifestData()['label'] === self.selectedPhysicalThingImageServiceName()) { + self.digitalResourceNameTile.transactionId = params.form.workflowId; + self.digitalResourceNameTile.save().then(function(data) { + self.digitalResourceTypeTile.resourceinstance_id = data.resourceinstance_id; + self.digitalResourceTypeTile.data[digitalResourceTypeNodeId](['305c62f0-7e3d-4d52-a210-b451491e6100']); // [IIIF Manifest] + self.digitalResourceTypeTile.transactionId = params.form.workflowId; + self.digitalResourceTypeTile.save(); + self.digitalResourceStatementTile.resourceinstance_id = data.resourceinstance_id; + self.digitalResourceStatementTile.transactionId = params.form.workflowId; + self.digitalResourceStatementTile.save().then(function(data) { + self.digitalResourceServiceTile.resourceinstance_id = data.resourceinstance_id; + self.digitalResourceServiceTile.data[digitalResourceServiceTypeNodeId](['e208df66-9e61-498b-8071-3024aa7bed30']); // web service + self.digitalResourceServiceTile.transactionId = params.form.workflowId; + self.digitalResourceServiceTile.save().then(function(data) { + self.digitalResourceServiceIdentifierTile.resourceinstance_id = data.resourceinstance_id; + self.digitalResourceServiceIdentifierTile.parenttile_id = data.tileid; + self.digitalResourceServiceIdentifierTile.transactionId = params.form.workflowId; + self.digitalResourceServiceIdentifierTile.save().then(function(data) { + params.form.savedData(data); + + var digitalReferenceTile = self.physicalThingDigitalReferenceTile(); + + var digitalSourceNodeId = 'a298ee52-8d59-11eb-a9c4-faffc265b501'; // Digital Source (E73) (physical thing) + + digitalReferenceTile.data[digitalSourceNodeId] = [{ + "resourceId": data.resourceinstance_id, + "ontologyProperty": "http://www.cidoc-crm.org/cidoc-crm/P67i_is_referred_to_by", + "inverseOntologyProperty": "http://www.cidoc-crm.org/cidoc-crm/P67_refers_to" + }]; + + var digitalReferenceTypeNodeId = 'f11e4d60-8d59-11eb-a9c4-faffc265b501'; // Digital Reference Type (E55) (physical thing) + digitalReferenceTile.data[digitalReferenceTypeNodeId] = '1497d15a-1c3b-4ee9-a259-846bbab012ed'; // Preferred Manifest concept value + + digitalReferenceTile.transactionId = params.form.workflowId; + digitalReferenceTile.save().then(function(data) { + params.form.complete(true); + params.form.saving(false); + }); + }); + }); + }); + }); + } + else { + var preferredManifestResourceData = self.physicalThingDigitalReferencePreferredManifestResourceData().find(function(manifestData) { return manifestData.displayname === self.selectedPhysicalThingImageServiceName(); }); + var alternateManifestResourceData = self.physicalThingDigitalReferenceAlternateManifestResourceData().find(function(manifestData) { return manifestData.displayname === self.selectedPhysicalThingImageServiceName(); }); + + var manifestResourceData = preferredManifestResourceData || alternateManifestResourceData; /* the same displayname should not exist in both values */ + + if (manifestResourceData && manifestResourceData.tiles) { + var digitalResourceServiceIdentifierNodegroupId = '56f8e26e-ca7c-11e9-9aa3-a4d18cec433a'; + + var matchingTile = manifestResourceData.tiles.find(function(tile) { + return tile.nodegroup_id === digitalResourceServiceIdentifierNodegroupId; + }); + + params.form.savedData(matchingTile); + } + params.form.complete(true); + params.form.saving(false); + } + }; + + this.reset = function() { + if (params.form.savedData()) { + var previouslyPersistedResourceId = params.form.savedData().resourceinstance_id; + + var preferredManifestResourceData = self.physicalThingDigitalReferencePreferredManifestResourceData().find(function(manifestData) { return manifestData.resourceid === previouslyPersistedResourceId; }); + var alternateManifestResourceData = self.physicalThingDigitalReferenceAlternateManifestResourceData().find(function(manifestData) { return manifestData.resourceid === previouslyPersistedResourceId; }); + + var manifestResourceData = preferredManifestResourceData || alternateManifestResourceData; /* the same displayname should not exist in both values */ + + if (manifestResourceData) { + self.selectedPhysicalThingImageServiceName(manifestResourceData.displayname); + } + } + }; + + this.openManifestManager = function() { + self.isManifestManagerHidden(false); + + }; + + this.handleExitFromManifestManager = function() { + self.isManifestManagerHidden(true); + + if ( + self.manifestData() + && self.manifestData()['label'] + && !self.physicalThingDigitalReferencePreferredManifestResourceData().find(function(manifestData) { return manifestData.displayname === self.manifestData()['label']; }) + ) { + self.physicalThingDigitalReferencePreferredManifestResourceData.push({ + 'displayname': self.manifestData()['label'], + 'thumbnail': self.manifestData().sequences[0].canvases[0].thumbnail + }); + + self.selectedPhysicalThingImageServiceName(self.manifestData()['label']); + } + }; + + this.getPhysicalThingDigitalReferenceData = function() { + $.getJSON( arches.urls.api_card + self.physicalThingResourceId ).then(function(data) { + var digitalReferenceCardData = data.cards.find(function(card) { + return card.nodegroup_id === '8a4ad932-8d59-11eb-a9c4-faffc265b501'; + }); + + var handlers = { + 'after-update': [], + 'tile-reset': [] + }; + + var graphModel = new GraphModel({ + data: { + nodes: data.nodes, + nodegroups: data.nodegroups, + edges: [] + }, + datatypes: data.datatypes + }); + + var digitalReferenceCard = new CardViewModel({ + card: digitalReferenceCardData, + graphModel: graphModel, + tile: null, + resourceId: ko.observable(self.physicalThingResourceId), + displayname: ko.observable(data.displayname), + handlers: handlers, + cards: data.cards, + tiles: data.tiles, + cardwidgets: data.cardwidgets, + userisreviewer: data.userisreviewer, + }); + + self.physicalThingDigitalReferenceCard(digitalReferenceCard); + self.physicalThingDigitalReferenceTile(digitalReferenceCard.getNewTile()); + }); + }; + + this.getThumnail = function(digitalResourceData) { + const digitalServiceTile = digitalResourceData.tiles.find(function(tile) { + return tile.nodegroup_id === digitalResourceServiceIdentifierNodegroupId; + }); + return window.fetch(digitalServiceTile.data[digitalResourceServiceIdentifierContentNodeId][arches.activeLanguage]['value']) + .then(function(response){ + if(response.ok) { + return response.json(); + } + }); + }; + + /* function used for getting the names of digital resources already related to physical thing */ + this.getPhysicalThingRelatedDigitalReferenceData = function(card) { + var digitalReferenceTypeNodeId = 'f11e4d60-8d59-11eb-a9c4-faffc265b501'; // Digital Reference Type (E55) (physical thing) + var digitalSourceNodeId = 'a298ee52-8d59-11eb-a9c4-faffc265b501'; // Digital Source (E73) (physical thing) + + var preferredManifestConceptValueId = '1497d15a-1c3b-4ee9-a259-846bbab012ed'; + var alternateManifestConceptValueId = "00d5a7a6-ff2f-4c44-ac85-7a8ab1a6fb70"; + + var tiles = card.tiles() || []; + + const hasManifest = tiles.some(function(tile) { + var digitalReferenceTypeValue = ko.unwrap(tile.data[digitalReferenceTypeNodeId]); + return (digitalReferenceTypeValue === ( preferredManifestConceptValueId || alternateManifestConceptValueId )); + }); + + if (!hasManifest){ + params.pageVm.loading(false); + } + + tiles.forEach(function(tile) { + var digitalReferenceTypeValue = ko.unwrap(tile.data[digitalReferenceTypeNodeId]); + + if (digitalReferenceTypeValue === ( preferredManifestConceptValueId || alternateManifestConceptValueId )) { + var physicalThingManifestResourceId = tile.data[digitalSourceNodeId]()[0].resourceId(); + + $.getJSON( arches.urls.api_card + physicalThingManifestResourceId ) + .then(function(data) { + self.getThumnail(data) + .then(function(json) { + data.thumbnail = json.sequences[0].canvases[0].thumbnail['@id']; + if (digitalReferenceTypeValue === preferredManifestConceptValueId) { + self.physicalThingDigitalReferencePreferredManifestResourceData.push(data); + } + else if (digitalReferenceTypeValue === alternateManifestConceptValueId) { + self.physicalThingDigitalReferenceAlternateManifestResourceData.push(data); + } + + var resourceData = self.getResourceDataAssociatedWithPreviouslyPersistedTile(data.displayname); + if (resourceData) { + self.selectedPhysicalThingImageServiceName(resourceData.displayname); + } + else if (!self.selectedPhysicalThingImageServiceName()) { + self.selectedPhysicalThingImageServiceName(self.physicalThingDigitalReferencePreferredManifestResourceData()[0].displayname); + } + }); + }) + .always(function() { + params.pageVm.loading(false); + }); + } + }); + }; + + this.initialize(); + } + + ko.components.register('add-chemical-analysis-images-image-step', { + viewModel: viewModel, + template: addChemicalAnalysisImagesImageStepTemplate + }); + return viewModel; +}); diff --git a/afs/media/js/views/components/workflows/select-observation-step.js b/afs/media/js/views/components/workflows/select-observation-step.js new file mode 100644 index 000000000..f2cb89fc1 --- /dev/null +++ b/afs/media/js/views/components/workflows/select-observation-step.js @@ -0,0 +1,183 @@ +define([ + 'knockout', + 'utils/resource', + 'templates/views/components/workflows/select-observation-step.htm', + 'viewmodels/card', +], function(ko, resourceUtils, selectObservationTemplate) { + + function viewModel(params) { + var self = this; + var componentParams = params.form.componentData.parameters; + this.physThingSetNodegroupId = 'cc5d6df3-d477-11e9-9f59-a4d18cec433a'; + this.physThingTypeNodeId = '8ddfe3ab-b31d-11e9-aff0-a4d18cec433a'; + this.physicalThingPartOfSetNodeId = '63e49254-c444-11e9-afbe-a4d18cec433a'; + this.observationPartOfPhysicalThingNodeId = 'cd412ac5-c457-11e9-9644-a4d18cec433a'; + this.partNodeGroupId = 'fec59582-8593-11ea-97eb-acde48001122'; + this.partManifestNodeId = '97c30c42-8594-11ea-97eb-acde48001122'; + this.manifestConcepts = [ + '1497d15a-1c3b-4ee9-a259-846bbab012ed', + '00d5a7a6-ff2f-4c44-ac85-7a8ab1a6fb70', + '305c62f0-7e3d-4d52-a210-b451491e6100' + ] + this.digitalReferenceTypeNodeId = 'f11e4d60-8d59-11eb-a9c4-faffc265b501'; + this.digitalReferenceNodeGroupId = '8a4ad932-8d59-11eb-a9c4-faffc265b501'; + this.save = params.form.save; + this.physicalThingGraphId = componentParams.graphids[0]; + this.projectGraphId = componentParams.graphids[1]; + this.datasetRoute = params.datasetRoute; + this.validateThing = componentParams.validateThing; + this.projectValue = ko.observable(); + this.projectNameValue = ko.observable(); + this.physicalThingValue = ko.observable(); + this.setsThatBelongToTheProject = ko.observable(); + this.hasSetWithPhysicalThing = ko.observable(); + this.isPhysicalThingValid = ko.observable(); + this.originalValue = params.form.value(); + this.physicalThingsThatBelongToSets = ko.observable(); + this.hasPhsyicalThingWithObservation = ko.observable(); + + this.updateValues = function(val){ + if (val !== null) { + self.physicalThingValue(val.physicalThing); + self.setsThatBelongToTheProject(val.physicalThingSet); + self.projectValue(val.project); + } + }; + + // update with saved values + if (params.value()) { + this.updateValues(params.value()); + } + + this.locked = params.form.locked; + + this.projectValue.subscribe(function(val){ + self.isPhysicalThingValid(null); + self.physicalThingValue(null); + if (val) { + var res = resourceUtils.lookupResourceInstanceData(val); + res.then( + function(data){ + self.projectNameValue(data._source.displayname); + let setTileResourceInstanceIds; + let setTile = data._source.tiles.find(function(tile){ + return tile.nodegroup_id === self.physThingSetNodegroupId; + }); + if (setTile && Object.keys(setTile.data).includes(self.physThingSetNodegroupId) && setTile.data[self.physThingSetNodegroupId].length) { + self.setsThatBelongToTheProject(null); + setTileResourceInstanceIds = setTile.data[self.physThingSetNodegroupId].map((instance) => instance.resourceId); + if (setTileResourceInstanceIds) { + self.setsThatBelongToTheProject(setTileResourceInstanceIds); + } + self.physicalThingValue(null); + + let query = {"op": "and"}; + query[self.physicalThingPartOfSetNodeId] = { + "op": "or", + "val": ko.unwrap(self.setsThatBelongToTheProject) + }; + + let res = resourceUtils.lookupResourceInstanceDataByQuery(query); + res.then( + function(data) { + physicalThingResourceIds = data.map((instance) => instance._source.resourceinstanceid) + if (physicalThingResourceIds) { + self.physicalThingsThatBelongToSets(physicalThingResourceIds) + } + console.log(data) + } + ) + } else { + self.hasPhsyicalThingWithObservation(false); + } + } + ); + } + }); + + + this.termFilter = ko.pureComputed(function(){ + if (ko.unwrap(self.physicalThingsThatBelongToSets)) { + self.hasSetWithPhysicalThing(true); + self.hasPhsyicalThingWithObservation(true); + var query = {"op": "and"}; + query[self.observationPartOfPhysicalThingNodeId] = { + "op": "or", + "val": ko.unwrap(self.physicalThingsThatBelongToSets) + }; + + + return function(term, queryString) { + queryString.set('advanced-search', JSON.stringify([query])); + if (term) { + queryString.set('term-filter', JSON.stringify([{"context":"", "id": term,"text": term,"type":"term","value": term,"inverted":false}])); + } + }; + } else { + return null; + } + }); + + this.physicalThingValue.subscribe(async (val) => { + // if the physical thing value isn't set correctly, return step value + // to original value + if (!val) { + params.value(self.originalValue); + return; + } + const physThing = (await resourceUtils.lookupResourceInstanceData(val))?._source; + + const digitalReferencesWithManifest = physThing.tiles. + filter(x => x.nodegroup_id == self.digitalReferenceNodeGroupId && + self.manifestConcepts.includes(x?.data?.[self.digitalReferenceTypeNodeId])); + const partsWithManifests = physThing.tiles.filter(x => + x.nodegroup_id == self.partNodeGroupId && + x.data?.[self.partManifestNodeId]?.features?.[0]?.properties?.manifest) + + // Below in defining the 'projectSet' we make sure that we know the collection that the physical thing came from. + // We need this in order to place child things in the same collection. + // It remains possible that if the selected physical thing belongs to two different collections + // within the same selected project we cannot know in which collection we should put it's samples/analysis areas. + // In this case we are defaulting to the first collection in the project's list of collections that contains the physical thing. + const setsThatBelongToTheSelectedThing = physThing.tiles.find(x => x.nodegroup_id === self.physicalThingPartOfSetNodeId)?.data[self.physicalThingPartOfSetNodeId].map(y => y.resourceId); + const projectSet = setsThatBelongToTheSelectedThing.find(setid => self.setsThatBelongToTheProject().includes(setid)) + + const analysisAreaValueId = '31d97bdd-f10f-4a26-958c-69cb5ab69af1'; + const sampleAreaValueId = '7375a6fb-0bfb-4bcf-81a3-6180cdd26123'; + const isArea = physThing.tiles.filter(x => + x.nodegroup_id == self.physThingTypeNodeId && + (x.data?.[self.physThingTypeNodeId].includes(analysisAreaValueId) || + x.data?.[self.physThingTypeNodeId].includes(sampleAreaValueId)) + ).length > 0; + + let canNonDestructiveObservation = false; + let canDestructiveObservation = false; + if (params.datasetRoute) { + canNonDestructiveObservation = (params.datasetRoute == 'non-destructive' && digitalReferencesWithManifest.length && partsWithManifests.length) + canDestructiveObservation= (params.datasetRoute == 'destructive' && !isArea) + } + + if(!self.validateThing || canNonDestructiveObservation || canDestructiveObservation){ + params.value({ + physThingName: physThing.displayname, + physicalThing: val, + projectSet: projectSet, + physicalThingSet: self.setsThatBelongToTheProject(), + project: self.projectValue(), + projectName: self.projectNameValue(), + }); + self.isPhysicalThingValid(true); + } else { + self.isPhysicalThingValid(false); + } + }); + + } + + ko.components.register('select-observation-step', { + viewModel: viewModel, + template: selectObservationTemplate + }); + + return viewModel; +}); diff --git a/afs/plugins/add-chemical-analysis-images-workflow.json b/afs/plugins/add-chemical-analysis-images-workflow.json new file mode 100644 index 000000000..6836ce280 --- /dev/null +++ b/afs/plugins/add-chemical-analysis-images-workflow.json @@ -0,0 +1,10 @@ +{ + "pluginid": "af06e949-5e16-49f0-b23e-e8529e8ce321", + "name": "Add chemical analysis images", + "icon": "fa fa-pie-chart", + "component": "views/components/plugins/add-chemical-analysis-images-workflow", + "componentname": "add-chemical-analysis-images-workflow", + "config": {"show":false}, + "slug": "add-chemical-analysis-images-workflow", + "sortorder": 1 +} diff --git a/afs/plugins/init-workflow.json b/afs/plugins/init-workflow.json index 6ae3711cc..82795fb9d 100644 --- a/afs/plugins/init-workflow.json +++ b/afs/plugins/init-workflow.json @@ -42,6 +42,15 @@ "circleColor": "#87b9e5", "desc": "Define regions of interest on an object or sample" }, + { + "workflowid": "af06e949-5e16-49f0-b23e-e8529e8ce321", + "slug":"add-chemical-analysis-images-workflow", + "name": "Add Chemical Analysis Images", + "icon": "fa fa-pie-chart", + "bgColor": "#6ea2d8", + "circleColor": "#87b9e5", + "desc": "Add Chemical Analysis Images" + }, { "workflowid": "afedd8cd-1ba7-43ec-b3c5-d0fab03525ca", "name": "Upload XY Data", diff --git a/afs/templates/views/components/plugins/add-chemical-analysis-images-workflow.htm b/afs/templates/views/components/plugins/add-chemical-analysis-images-workflow.htm new file mode 100644 index 000000000..e2c360f69 --- /dev/null +++ b/afs/templates/views/components/plugins/add-chemical-analysis-images-workflow.htm @@ -0,0 +1,2 @@ +{% extends "views/components/plugins/workflow.htm" %} +{% load i18n %} diff --git a/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.htm b/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.htm new file mode 100644 index 000000000..78d819579 --- /dev/null +++ b/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.htm @@ -0,0 +1,61 @@ +{% load i18n %} + +
+
+
{% trans 'Related Project/Object' %}
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+ + + +
+
{% trans 'Region(s) of Interest' %}
+
+
+
+
+
+
+
+
+
+ +
+ +
+ +
+
+ diff --git a/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.htm b/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.htm new file mode 100644 index 000000000..300c12795 --- /dev/null +++ b/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.htm @@ -0,0 +1,79 @@ + +
+

+ Select an existing image service for your object that you can use to draw the locations of your observations. + Or upload image(s) to create a new service. +

+ + +
+ + + + + +
+ +
+ + + +
+ +
+ +
\ No newline at end of file diff --git a/afs/templates/views/components/workflows/select-observation-step.htm b/afs/templates/views/components/workflows/select-observation-step.htm new file mode 100644 index 000000000..4c5921108 --- /dev/null +++ b/afs/templates/views/components/workflows/select-observation-step.htm @@ -0,0 +1,56 @@ +{% load i18n %} +
+
+
Project observation file
+
+
+ +
+
+ + Select an Observation + + + Select an Object that has an Area of interest + + + Select a Sample of interest + +
+
+
+ + +
+ This project has no associated Objects. Your project must have an associated Object Collection with an Object before proceeding. +
+ + +
+ + You have to select an object with the analysis areas. Please complete the analysis area workflow or start the workflow over and select the sample dataset type. + + + You have to select a sample. Please complete the sample taking workflow or start the workflow over and select the area dataset type. + +
+ +
From 83cd7093f1fe25ad5a2a1254093b9e36c9f5a340 Mon Sep 17 00:00:00 2001 From: Aaron Gundel Date: Mon, 26 Jun 2023 16:08:23 -0600 Subject: [PATCH 002/342] fix for #1204 and stylic tweak --- .../workflows/project-report-workflow/add-annotations.htm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/afs/templates/views/components/workflows/project-report-workflow/add-annotations.htm b/afs/templates/views/components/workflows/project-report-workflow/add-annotations.htm index 49eaceb45..2b59d6f3c 100644 --- a/afs/templates/views/components/workflows/project-report-workflow/add-annotations.htm +++ b/afs/templates/views/components/workflows/project-report-workflow/add-annotations.htm @@ -29,7 +29,7 @@
Name of Summary
- +
@@ -48,7 +48,7 @@
- + From c77ce9671ad14402afd82e25c8cf26737d0a4c15 Mon Sep 17 00:00:00 2001 From: Ryan Anderson Date: Mon, 26 Jun 2023 17:01:21 -0700 Subject: [PATCH 003/342] Add chemical analysis workflow, re #1134 --- .../add-chemical-analysis-images-workflow.js | 10 +- ...add-chemical-analysis-images-final-step.js | 122 ++------- ...add-chemical-analysis-images-image-step.js | 237 +++++++++++++++++- .../workflows/select-observation-step.js | 46 +++- afs/templates/javascript.htm | 1 + ...dd-chemical-analysis-images-final-step.htm | 37 ++- ...dd-chemical-analysis-images-image-step.htm | 1 + .../workflows/select-observation-step.htm | 4 +- afs/urls.py | 6 + 9 files changed, 329 insertions(+), 135 deletions(-) diff --git a/afs/media/js/views/components/plugins/add-chemical-analysis-images-workflow.js b/afs/media/js/views/components/plugins/add-chemical-analysis-images-workflow.js index dfc11b1a4..73682a949 100644 --- a/afs/media/js/views/components/plugins/add-chemical-analysis-images-workflow.js +++ b/afs/media/js/views/components/plugins/add-chemical-analysis-images-workflow.js @@ -66,7 +66,8 @@ define([ tilesManaged: 'one', parameters: { graphid: '707cbd78-ca7a-11e9-990b-a4d18cec433a', /* Digital Resources */ - physicalThingResourceId: "['select-project']['select-phys-thing']['physicalThing']" + physicalThingResourceId: "['select-project']['select-observation']['phsyicalThingResourceId']", + observationResourceId: "['select-project']['select-observation']['observation']" }, }, ], @@ -85,10 +86,11 @@ define([ uniqueInstanceName: 'add-chemical-analysis-images-final', tilesManaged: 'none', parameters: { - sampleObjectResourceId: "['select-project']['select-phys-thing']['physicalThing']", - relatedProjectData: "['select-project']['select-phys-thing']", + observationResourceId: "['select-project']['select-observation']['observation']", + relatedProjectData: "['select-project']['select-observation']", imageStepData: "['image-step']['image-service-instance'][0]['data']", - digitalReferenceResourceId: "['image-step']['image-service-instance'][0]['resourceinstance_id']" + digitalResourcesIds: "['image-step']['image-service-instance']['digitalResourcesIds']", + manifestResourceId: "['image-step']['image-service-instance']['manifestResourceId']", }, }, ], diff --git a/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.js b/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.js index ec69d4a5e..5c4c78522 100644 --- a/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.js +++ b/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.js @@ -10,115 +10,39 @@ define([ function viewModel(params) { var self = this; - - params.form.resourceId(params.sampleObjectResourceId); - const digitalResourceServiceIdentifierContentNodeId = '56f8e9bd-ca7c-11e9-b578-a4d18cec433a'; - const manifestUrl = params.imageStepData[digitalResourceServiceIdentifierContentNodeId][arches.activeLanguage]['value']; - const digitalReferenceResourceId = params.digitalReferenceResourceId; - - this.regionInstances = params.regionsStepData?.data.map(function(data){ - return { - regionName: data.data["3e541cc6-859b-11ea-97eb-acde48001122"], - regionResource: data.data["b240c366-8594-11ea-97eb-acde48001122"][0]["resourceId"], - }; - }); - const currentAnalysisAreas = params.regionsStepData?.currentAnalysisAreas; + params.form.resourceId(params.relatedProjectData.observation); + self.relatedDigitalResources = ko.observableArray() + self.workflowDigitalResources = ko.observableArray() + self.workflowManifestResource = ko.observable() + self.digitalResourcesIds = params.digitalResourcesIds.digitalResourceInstancesIds; + self.manifestResourceId = params.manifestResourceId.ManifestResourceId; SummaryStep.apply(this, [params]); - this.objectAnnotations = ko.observableArray(); this.resourceData.subscribe(function(val){ this.displayName = val['displayname'] || 'unnamed'; - const digitalReference = val.resource['Digital Reference'].find(function(val){ - return val['Digital Source']['resourceId'] === digitalReferenceResourceId; - }); this.reportVals = { projectName: {'name': 'Project', 'value': params.relatedProjectData.projectName, 'resourceid': params.relatedProjectData.project}, - parentObject: {'name': 'Object', 'value': this.getResourceValue(val.resource, ['part of', '@display_value'])}, - digitalReference: {'name': 'Image Service', 'value': digitalReference['Digital Source']["@display_value"]}, + observationName: {'name': 'Observation', 'value': params.relatedProjectData.observationName, 'resourceid': params.relatedProjectData.observation}, }; - var annotationCollection = {}; - self.regionResourceIds = self.regionInstances?.map(x => x.regionResource); - val.resource['Part Identifier Assignment'].forEach(function(annotation){ - const annotationResourceId = self.getResourceValue(annotation,['Part Identifier Assignment_Physical Part of Object','resourceId']); - const annotationName = self.getResourceValue(annotation,['Part Identifier Assignment_Physical Part of Object','@display_value']); - const annotationLabel = self.getResourceValue(annotation,['Part Identifier Assignment_Label','@display_value']); - const annotator = self.getResourceValue(annotation,['Part Identifier Assignment_Annotator','@display_value']); - const annotationStr = self.getResourceValue(annotation,['Part Identifier Assignment_Polygon Identifier','@display_value']); - const tileId = self.getResourceValue(annotation,['Part Identifier Assignment_Polygon Identifier','@tile_id']); - if (annotationStr) { - const annotationJson = JSON.parse(annotationStr.replaceAll("'",'"')); - if (annotationJson.features.length > 0){ - const currentManifestUrl = annotation['Part Identifier Assignment_Polygon Identifier']['geojson']['features'][0]['properties']['manifest']; - if (currentManifestUrl === manifestUrl){ - const canvas = annotationJson.features[0].properties.canvas; - annotationJson.features.forEach(function(feature){ - feature.properties.tileId = tileId; - }); - if (canvas in annotationCollection) { - annotationCollection[canvas].push({ - resourceId: annotationResourceId, - tileId: tileId, - annotationName: annotationName, - annotationLabel: annotationLabel, - annotator: annotator, - annotationJson: annotationJson, - }); - } else { - annotationCollection[canvas] = [{ - resourceId: annotationResourceId, - tileId: tileId, - annotationName: annotationName, - annotationLabel: annotationLabel, - annotator: annotator, - annotationJson: annotationJson, - }]; - } - } - } - } - }); - - for (const canvas in annotationCollection) { - let name; - let annotationCombined; - let info = []; - annotationCollection[canvas].forEach(function(annotation){ - name = annotation.annotationName; - if (annotationCombined) { - annotationCombined.features = annotationCombined.features.concat(annotation.annotationJson.features); - } else { - annotationCombined = annotation.annotationJson; - } - if (currentAnalysisAreas?.includes(annotation.tileId)) { - info.push({ - tileId: annotation.tileId, - name: annotation.annotationName, - 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; - }); - } - }); - - const leafletConfig = self.prepareAnnotation(annotationCombined); - if (info.length > 0) { - self.objectAnnotations.push({ - name: name, - info: info, - leafletConfig: leafletConfig, - featureCollection: annotationCombined, - }); - } - } this.loading(false); }, this); + + this.getWorkflowResourceData = async function(resourceid) { + const response = await window.fetch(this.urls.api_resources(resourceid) + '?format=json&compact=false&v=beta') + return await response.json() + }; + + (async (val) => { + self.workflowDigitalResources(await Promise.all(self.digitalResourcesIds.map( async function(resourceid){ + return await self.getWorkflowResourceData(resourceid); + }))); + })(); + + (async (val) => { + self.workflowManifestResource(await self.getWorkflowResourceData(self.manifestResourceId)) + })() + } ko.components.register('add-chemical-analysis-images-final-step', { diff --git a/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.js b/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.js index a0d4fb871..5adf09f5e 100644 --- a/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.js +++ b/afs/media/js/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.js @@ -6,9 +6,10 @@ define([ 'knockout-mapping', 'models/graph', 'viewmodels/card', + 'js-cookie', 'templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-image-step.htm', 'views/components/plugins/manifest-manager', -], function(_, $, arches, ko, koMapping, GraphModel, CardViewModel, addChemicalAnalysisImagesImageStepTemplate) { +], function(_, $, arches, ko, koMapping, GraphModel, CardViewModel, Cookies, addChemicalAnalysisImagesImageStepTemplate) { function viewModel(params) { var self = this; params.pageVm.loading(true); @@ -28,6 +29,27 @@ define([ } }); + this.digitalResourcesInstanceIds = ko.observableArray(); + + this.observationResourceId = koMapping.toJS(params.observationResourceId); + + this.observationDigitalReferenceCard = ko.observable(); + this.observationDigitalReferenceCard.subscribe(function(card) { + //---// + self.getPhysicalThingRelatedDigitalReferenceData(card); + }); + + this.observationResourceInstanceId = ko.observable(); + this.observationDigitalReferenceTile = ko.observable(); + + this.observationDigitalReferencePreferredManifestResourceData = ko.observableArray(); + this.observationDigitalReferenceAlternateManifestResourceData = ko.observableArray(); + + + + + + this.physicalThingResourceId = koMapping.toJS(params.physicalThingResourceId); this.physicalThingDigitalReferenceCard = ko.observable(); @@ -40,6 +62,9 @@ define([ this.physicalThingDigitalReferencePreferredManifestResourceData = ko.observableArray(); this.physicalThingDigitalReferenceAlternateManifestResourceData = ko.observableArray(); + + + var digitalResourceNameNodegroupId = 'd2fdae3d-ca7a-11e9-ad84-a4d18cec433a'; var digitalResourceNameCard = params.form.topCards.find(function(topCard) { return topCard.nodegroupid === digitalResourceNameNodegroupId; @@ -72,6 +97,14 @@ define([ }); this.digitalResourceServiceIdentifierTile = digitalResourceServiceIdentifierCard.getNewTile(); + + var digitalResourceFileNodegroupId = '7c486328-d380-11e9-b88e-a4d18cec433a'; + var digitalResourceFileCard = params.form.topCards.find(function(topCard) { + return topCard.nodegroupid === digitalResourceFileNodegroupId; + }); + this.digitalResourceFileTile = digitalResourceFileCard.getNewTile(); + + const digitalResourceNameContentNodeId = 'd2fdc2fa-ca7a-11e9-8ffb-a4d18cec433a'; const digitalResourceStatementContentNodeId = 'da1fbca1-ca7a-11e9-8256-a4d18cec433a'; const digitalResourceServiceTypeConformanceNodeId = 'cec360bd-ca7f-11e9-9ab7-a4d18cec433a'; @@ -80,6 +113,8 @@ define([ const digitalResourceServiceTypeNodeId= '5ceedd21-ca7c-11e9-a60f-a4d18cec433a'; const digitalResourceTypeNodeId = '09c1778a-ca7b-11e9-860b-a4d18cec433a'; + const digitalResourceFileNodeId = '7c486328-d380-11e9-b88e-a4d18cec433a'; + this.buildStrObject = str => { return {[arches.activeLanguage]: { "value": str, @@ -87,6 +122,55 @@ define([ }}; }; + this.manifestManagerFormData = ko.observable(); + this.formData = new window.FormData(); + + this.saveDatasetFile = (formData, file) => { + //Tile structure for the Digital Resource 'File' nodegroup + + if(file) { + let fileInfo; + + if (!ko.unwrap(file.tileId)) { + fileInfo = { + name: file.name, + accepted: true, + height: file.height, + lastModified: file.lastModified, + size: file.size, + status: file.status, + type: file.type, + width: file.width, + url: null, + uploaded: ko.observable(false), + // eslint-disable-next-line camelcase + file_id: null, + index: 0, + content: null, + error: file.error, + }; + + self.fileData.push(JSON.stringify(fileInfo)); + // self.fileDataPreloaded.push(new Blob(), file.name) + // formData.append(`file-list_${digitalResourceFileNodegroupId}_preloaded`, new Blob(), file.name); + } + } + }; + + + + this.fileData = Array(); + this.fileDataPreloaded = Array(); + this.manifestManagerFormData.subscribe(function(manifestManagerFormData) { + var files = manifestManagerFormData.getAll('files'); + Array.from(files).forEach(file => { + // Then save a file tile to the digital resource for each associated file + self.saveDatasetFile(self.formData, file); + }); + + self.formData.append('file_data', JSON.stringify(self.fileData)); + // self.formData.append('file_data_preloaded', JSON.stringify(self.fileDataPreloaded)); + }); this.manifestData = ko.observable(); this.manifestData.subscribe(function(manifestData) { @@ -112,6 +196,10 @@ define([ params.form.save = self.save; params.form.reset = self.reset; + if (!self.observationDigitalReferenceCard() || !self.observationDigitalReferenceTile()) { + self.getObservationDigitalReferenceData(); + } + if (!self.physicalThingDigitalReferenceCard() || !self.physicalThingDigitalReferenceTile()) { self.getPhysicalThingDigitalReferenceData(); } @@ -159,15 +247,16 @@ define([ self.digitalResourceServiceIdentifierTile.resourceinstance_id = data.resourceinstance_id; self.digitalResourceServiceIdentifierTile.parenttile_id = data.tileid; self.digitalResourceServiceIdentifierTile.transactionId = params.form.workflowId; - self.digitalResourceServiceIdentifierTile.save().then(function(data) { + self.digitalResourceServiceIdentifierTile.save().then(async function(data) { params.form.savedData(data); var digitalReferenceTile = self.physicalThingDigitalReferenceTile(); - var digitalSourceNodeId = 'a298ee52-8d59-11eb-a9c4-faffc265b501'; // Digital Source (E73) (physical thing) + var digitalResourceInstanceId = data.resourceinstance_id + digitalReferenceTile.data[digitalSourceNodeId] = [{ - "resourceId": data.resourceinstance_id, + "resourceId": digitalResourceInstanceId, "ontologyProperty": "http://www.cidoc-crm.org/cidoc-crm/P67i_is_referred_to_by", "inverseOntologyProperty": "http://www.cidoc-crm.org/cidoc-crm/P67_refers_to" }]; @@ -180,7 +269,51 @@ define([ params.form.complete(true); params.form.saving(false); }); - }); + + // Do the save again for observation + if (self.observationDigitalReferenceTile()) { + self.observationResourceInstanceId(self.observationDigitalReferenceTile().resourceinstance_id); + var digitalReferenceTile = self.observationDigitalReferenceTile(); + var digitalSourceNodeId = '0ae14d2a-8e30-11eb-a9c4-faffc265b501'; // Digital Source (E73) (observation) + + digitalReferenceTile.data[digitalSourceNodeId] = [{ + "resourceId": digitalResourceInstanceId, + "ontologyProperty": "http://www.cidoc-crm.org/cidoc-crm/P67i_is_referred_to_by", + "inverseOntologyProperty": "http://www.cidoc-crm.org/cidoc-crm/P67_refers_to" + }]; + + var digitalReferenceTypeNodeId = '0ae14c58-8e30-11eb-a9c4-faffc265b501'; // Digital Reference Type (E55) (observation) + digitalReferenceTile.data[digitalReferenceTypeNodeId] = '1497d15a-1c3b-4ee9-a259-846bbab012ed'; // Preferred Manifest concept value + + digitalReferenceTile.transactionId = params.form.workflowId; + digitalReferenceTile.save().then(function(data) { + params.form.complete(true); + params.form.saving(false); + }); + } + + self.formData.append("transaction_id", params.form.workflowId); + self.formData.append("observation_id", self.observationResourceInstanceId()); + + const resp = await fetch(arches.urls.add_chemical_analysis_images_file_upload, { + method: 'POST', + credentials: 'include', + body: self.formData, + headers: { + "X-CSRFToken": Cookies.get('csrftoken') + } + }) + var response = await resp.json(); + response.digitalResourceInstanceIds.forEach(function(d){ + self.digitalResourcesInstanceIds.push(d); + }) + + data.digitalResourceInstancesIds = []; + data.digitalResourceInstancesIds = self.digitalResourcesInstanceIds(); + data.ManifestResourceId = data.resourceinstance_id; + params.form.savedData(data); + params.form.value(data); + }) }); }); }); @@ -280,7 +413,45 @@ define([ }); }; - this.getThumnail = function(digitalResourceData) { + this.getObservationDigitalReferenceData = function() { + $.getJSON( arches.urls.api_card + self.observationResourceId ).then(function(data) { + var digitalReferenceCardData = data.cards.find(function(card) { + return card.nodegroup_id === '0ae149ba-8e30-11eb-a9c4-faffc265b501'; + }); + + var handlers = { + 'after-update': [], + 'tile-reset': [] + }; + + var graphModel = new GraphModel({ + data: { + nodes: data.nodes, + nodegroups: data.nodegroups, + edges: [] + }, + datatypes: data.datatypes + }); + + var digitalReferenceCard = new CardViewModel({ + card: digitalReferenceCardData, + graphModel: graphModel, + tile: null, + resourceId: ko.observable(self.observationResourceId), + displayname: ko.observable(data.displayname), + handlers: handlers, + cards: data.cards, + tiles: data.tiles, + cardwidgets: data.cardwidgets, + userisreviewer: data.userisreviewer, + }); + + self.observationDigitalReferenceCard(digitalReferenceCard); + self.observationDigitalReferenceTile(digitalReferenceCard.getNewTile()); + }); + }; + + this.getThumbnail = function(digitalResourceData) { const digitalServiceTile = digitalResourceData.tiles.find(function(tile) { return tile.nodegroup_id === digitalResourceServiceIdentifierNodegroupId; }); @@ -319,7 +490,59 @@ define([ $.getJSON( arches.urls.api_card + physicalThingManifestResourceId ) .then(function(data) { - self.getThumnail(data) + self.getThumbnail(data) + .then(function(json) { + data.thumbnail = json.sequences[0].canvases[0].thumbnail['@id']; + if (digitalReferenceTypeValue === preferredManifestConceptValueId) { + self.physicalThingDigitalReferencePreferredManifestResourceData.push(data); + } + else if (digitalReferenceTypeValue === alternateManifestConceptValueId) { + self.physicalThingDigitalReferenceAlternateManifestResourceData.push(data); + } + + var resourceData = self.getResourceDataAssociatedWithPreviouslyPersistedTile(data.displayname); + if (resourceData) { + self.selectedPhysicalThingImageServiceName(resourceData.displayname); + } + else if (!self.selectedPhysicalThingImageServiceName()) { + self.selectedPhysicalThingImageServiceName(self.physicalThingDigitalReferencePreferredManifestResourceData()[0].displayname); + } + }); + }) + .always(function() { + params.pageVm.loading(false); + }); + } + }); + }; + + this.getObservationRelatedDigitalReferenceData = function(card) { + var digitalReferenceTypeNodeId = '0ae14c58-8e30-11eb-a9c4-faffc265b501'; // Digital Reference Type (E55) (observation) + var digitalSourceNodeId = '0ae14d2a-8e30-11eb-a9c4-faffc265b501'; // Digital Source (E73) (observation) + + var preferredManifestConceptValueId = '1497d15a-1c3b-4ee9-a259-846bbab012ed'; + var alternateManifestConceptValueId = "00d5a7a6-ff2f-4c44-ac85-7a8ab1a6fb70"; + + var tiles = card.tiles() || []; + + const hasManifest = tiles.some(function(tile) { + var digitalReferenceTypeValue = ko.unwrap(tile.data[digitalReferenceTypeNodeId]); + return (digitalReferenceTypeValue === ( preferredManifestConceptValueId || alternateManifestConceptValueId )); + }); + + if (!hasManifest){ + params.pageVm.loading(false); + } + + tiles.forEach(function(tile) { + var digitalReferenceTypeValue = ko.unwrap(tile.data[digitalReferenceTypeNodeId]); + + if (digitalReferenceTypeValue === ( preferredManifestConceptValueId || alternateManifestConceptValueId )) { + var physicalThingManifestResourceId = tile.data[digitalSourceNodeId]()[0].resourceId(); + + $.getJSON( arches.urls.api_card + physicalThingManifestResourceId ) + .then(function(data) { + self.getThumbnail(data) .then(function(json) { data.thumbnail = json.sequences[0].canvases[0].thumbnail['@id']; if (digitalReferenceTypeValue === preferredManifestConceptValueId) { diff --git a/afs/media/js/views/components/workflows/select-observation-step.js b/afs/media/js/views/components/workflows/select-observation-step.js index f2cb89fc1..14777dbf5 100644 --- a/afs/media/js/views/components/workflows/select-observation-step.js +++ b/afs/media/js/views/components/workflows/select-observation-step.js @@ -10,6 +10,7 @@ define([ var componentParams = params.form.componentData.parameters; this.physThingSetNodegroupId = 'cc5d6df3-d477-11e9-9f59-a4d18cec433a'; this.physThingTypeNodeId = '8ddfe3ab-b31d-11e9-aff0-a4d18cec433a'; + this.observationTypeNodeId = '7b97ee23-c457-11e9-8ce3-a4d18cec433a'; this.physicalThingPartOfSetNodeId = '63e49254-c444-11e9-afbe-a4d18cec433a'; this.observationPartOfPhysicalThingNodeId = 'cd412ac5-c457-11e9-9644-a4d18cec433a'; this.partNodeGroupId = 'fec59582-8593-11ea-97eb-acde48001122'; @@ -29,15 +30,18 @@ define([ this.projectValue = ko.observable(); this.projectNameValue = ko.observable(); this.physicalThingValue = ko.observable(); + this.observationValue = ko.observable(); this.setsThatBelongToTheProject = ko.observable(); this.hasSetWithPhysicalThing = ko.observable(); this.isPhysicalThingValid = ko.observable(); + this.isObservationValid = ko.observable(); this.originalValue = params.form.value(); this.physicalThingsThatBelongToSets = ko.observable(); this.hasPhsyicalThingWithObservation = ko.observable(); this.updateValues = function(val){ if (val !== null) { + self.observationValue(val.observation); self.physicalThingValue(val.physicalThing); self.setsThatBelongToTheProject(val.physicalThingSet); self.projectValue(val.project); @@ -54,6 +58,7 @@ define([ this.projectValue.subscribe(function(val){ self.isPhysicalThingValid(null); self.physicalThingValue(null); + self.observationValue(null); if (val) { var res = resourceUtils.lookupResourceInstanceData(val); res.then( @@ -84,7 +89,6 @@ define([ if (physicalThingResourceIds) { self.physicalThingsThatBelongToSets(physicalThingResourceIds) } - console.log(data) } ) } else { @@ -118,6 +122,42 @@ define([ } }); + + this.observationValue.subscribe(async(val) => { + // if the physical thing value isn't set correctly, return step value + // to original value + if (!val) { + params.value(self.originalValue); + return; + } + + const observation = (await resourceUtils.lookupResourceInstanceData(val))?._source; + + physicalThingObervationTile = observation.tiles.find(function(tile){ + return tile.nodegroup_id === self.observationPartOfPhysicalThingNodeId; + }); + + phsyicalThingResourceId = physicalThingObervationTile.data[self.observationPartOfPhysicalThingNodeId][0].resourceId + + if(!self.validateThing || canNonDestructiveObservation || canDestructiveObservation){ + params.value({ + observationName: observation.displayname, + observation: val, + // projectSet: projectSet, + phsyicalThingResourceId: phsyicalThingResourceId, + physicalThingSet: self.setsThatBelongToTheProject(), + project: self.projectValue(), + projectName: self.projectNameValue(), + }); + self.isObservationValid(true); + } else { + self.isObservationValid(false); + } + + + + }) + this.physicalThingValue.subscribe(async (val) => { // if the physical thing value isn't set correctly, return step value // to original value @@ -140,7 +180,7 @@ define([ // within the same selected project we cannot know in which collection we should put it's samples/analysis areas. // In this case we are defaulting to the first collection in the project's list of collections that contains the physical thing. const setsThatBelongToTheSelectedThing = physThing.tiles.find(x => x.nodegroup_id === self.physicalThingPartOfSetNodeId)?.data[self.physicalThingPartOfSetNodeId].map(y => y.resourceId); - const projectSet = setsThatBelongToTheSelectedThing.find(setid => self.setsThatBelongToTheProject().includes(setid)) + // const projectSet = setsThatBelongToTheSelectedThing.find(setid => self.setsThatBelongToTheProject().includes(setid)) const analysisAreaValueId = '31d97bdd-f10f-4a26-958c-69cb5ab69af1'; const sampleAreaValueId = '7375a6fb-0bfb-4bcf-81a3-6180cdd26123'; @@ -161,7 +201,7 @@ define([ params.value({ physThingName: physThing.displayname, physicalThing: val, - projectSet: projectSet, + // projectSet: projectSet, physicalThingSet: self.setsThatBelongToTheProject(), project: self.projectValue(), projectName: self.projectNameValue(), diff --git a/afs/templates/javascript.htm b/afs/templates/javascript.htm index 1aca6c784..1a33b6927 100644 --- a/afs/templates/javascript.htm +++ b/afs/templates/javascript.htm @@ -13,6 +13,7 @@ upload_dataset_select_dataset_files_step = "{% url 'upload_dataset_select_dataset_files_step' %}" upload_dataset_file_renderer = '(tileid)=>{return "{% url "upload_dataset_file_renderer" "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" %}".replace("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", tileid)}', format_render_map = '(format)=>{return "{% url "format_render_map" "aaaaaaaa" %}".replace("aaaaaaaa", format)}' + add_chemical_analysis_images_file_upload = "{% url 'add_chemical_analysis_images_file_upload' %}" >
{% endblock arches_urls %} diff --git a/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.htm b/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.htm index 78d819579..0cfb3b893 100644 --- a/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.htm +++ b/afs/templates/views/components/workflows/add-chemical-analysis-images-workflow/add-chemical-analysis-images-final-step.htm @@ -2,7 +2,7 @@
-
{% trans 'Related Project/Object' %}
+
{% trans 'Related Project/Observation' %}
@@ -14,10 +14,10 @@
{% trans 'Related Project/Object' %}
@@ -25,37 +25,34 @@
{% trans 'Related Project/Object' %}
-