-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3352 from AtlasOfLivingAustralia/feature/issue2880
Feature/issue2880
- Loading branch information
Showing
64 changed files
with
69,864 additions
and
1,466 deletions.
There are no files selected for viewing
199 changes: 199 additions & 0 deletions
199
grails-app/assets/components/javascript/associated-orgs.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/* | ||
* Copyright (C) 2022 Atlas of Living Australia | ||
* All Rights Reserved. | ||
* | ||
* The contents of this file are subject to the Mozilla Public | ||
* License Version 1.1 (the "License"); you may not use this file | ||
* except in compliance with the License. You may obtain a copy of | ||
* the License at http://www.mozilla.org/MPL/ | ||
* | ||
* Software distributed under the License is distributed on an "AS | ||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
* implied. See the License for the specific language governing | ||
* rights and limitations under the License. | ||
*/ | ||
/** | ||
* This component renders a list of organisations and their relationship to an entity | ||
*/ | ||
ko.components.register('associated-orgs', { | ||
|
||
/** | ||
* @param params an object with the following keys: | ||
* externalIds: an observable array of objects, each object will have two observables, idType and externalId. | ||
* externalIdTypes: an array of label/value pairs that define the selectable options for the idType | ||
* validationNamespace: a string to store the validation function in the global namespace for use by jquery validation engine | ||
* validate: a jquery-validation-engine style function that will validate the external ids. (Note this function | ||
* should return a string containing the error if the validation fails). | ||
*/ | ||
viewModel: function (params) { | ||
var self = this; | ||
self.organisationSearchUrl = params.organisationSearchUrl; | ||
self.organisationViewUrl = params.organisationViewUrl; | ||
self.displayName = params.displayName; | ||
self.relationshipTypes = params.relationshipTypes; | ||
|
||
var $modal = $('#add-or-edit-organisation'); | ||
$modal.find('form').validationEngine(); | ||
|
||
function AssociatedOrg(associatedOrg) { | ||
|
||
associatedOrg = associatedOrg || {}; | ||
this.name = ko.observable(associatedOrg.name); | ||
this.organisationName = ko.observable(associatedOrg.organisationName); | ||
this.description = ko.observable(associatedOrg.description); | ||
this.organisationId = ko.observable(associatedOrg.organisationId); | ||
this.fromDate = ko.observable(associatedOrg.fromDate).extend({simpleDate:false}); | ||
this.toDate = ko.observable(associatedOrg.toDate).extend({simpleDate:false}); | ||
|
||
this.toJSON = function() { | ||
return ko.mapping.toJS(this); | ||
} | ||
} | ||
|
||
self.associatedOrgs = ko.observableArray(_.map(params.associatedOrgs(), function(org) { | ||
return new AssociatedOrg(org); | ||
})); | ||
// Overwrites the associatedOrgs observable with the mapped values so they are editable and changes in | ||
// this component are reflected in the parent component. | ||
params.associatedOrgs(self.associatedOrgs()); | ||
|
||
self.validationNamespace = params.validationNamespace; | ||
|
||
self.organisationSearchUrl = params.organisationSearchUrl; | ||
self.allowedNames = ko.observableArray([]); | ||
|
||
self.removeAssociatedOrg = function (org) { | ||
self.associatedOrgs.remove(org); | ||
} | ||
|
||
// Maintains the state of which organisation is being edited or added | ||
self.selectedOrganisation = null; | ||
|
||
self.addAssociatedOrg = function () { | ||
self.selectedOrganisation = new AssociatedOrg(); | ||
openEditModal(); | ||
} | ||
|
||
self.editAssociatedOrg = function (organisation) { | ||
self.selectedOrganisation = organisation; | ||
openEditModal(); | ||
} | ||
|
||
function openEditModal() { | ||
|
||
var orgId = self.selectedOrganisation.organisationId(); | ||
if (orgId) { | ||
findMatchingOrganisation(orgId, function(matchingOrg) { | ||
if (matchingOrg && matchingOrg._source) { | ||
self.allowedNames(self.allowedNamesForOrganisation(matchingOrg._source)); | ||
copy(self.selectedOrganisation, self.editableOrganisation); | ||
$('#searchOrganisation').val(matchingOrg._source.name); | ||
$modal.modal('show'); | ||
} | ||
else { | ||
bootbox.alert("Unable to edit organisation") | ||
} | ||
}); | ||
} | ||
else { | ||
self.clearSelectedOrganisation(); | ||
$modal.modal('show'); | ||
} | ||
|
||
} | ||
|
||
function findMatchingOrganisation(organisationId, callback) { | ||
$.get(self.organisationSearchUrl+'?searchTerm='+organisationId).done(function(results) { | ||
if (results && results.hits && results.hits.hits) { | ||
var matchingOrg = _.find(results.hits.hits, function (hit) { | ||
return hit._id == organisationId; | ||
}); | ||
|
||
callback(matchingOrg); | ||
} | ||
}); | ||
} | ||
|
||
self.okPressed = function () { | ||
var valid = $modal.find('form').validationEngine('validate'); | ||
if (!valid) { | ||
return; | ||
} | ||
if (!_.contains(self.associatedOrgs(), self.selectedOrganisation)) { | ||
self.associatedOrgs.push(self.selectedOrganisation); | ||
} | ||
copy(self.editableOrganisation, self.selectedOrganisation); | ||
self.close(); | ||
} | ||
|
||
self.close = function() { | ||
$modal.modal('hide'); | ||
} | ||
|
||
function copy(source, destination) { | ||
destination.organisationId(source.organisationId()); | ||
destination.name(source.name()); | ||
destination.description(source.description()); | ||
destination.fromDate(source.fromDate()); | ||
destination.toDate(source.toDate()); | ||
} | ||
|
||
self.allowedNamesForOrganisation = function(organisation) { | ||
var allowedNames = []; | ||
allowedNames.push(organisation.name); | ||
if (organisation.entityName) { | ||
allowedNames.push(organisation.entityName); | ||
} | ||
if (organisation.businessNames) { | ||
allowedNames = allowedNames.concat(organisation.businessNames); | ||
} | ||
if (organisation.contractNames) { | ||
allowedNames = allowedNames.concat(organisation.contractNames); | ||
} | ||
return allowedNames; | ||
} | ||
|
||
/** | ||
* This method is designed to be used by the jquery validation engine so a passed validation will | ||
* return undefined / null, and a failed validation will return an error message. | ||
* @returns {*} A message to display if validation failed. | ||
*/ | ||
self.associatedOrgValidation = function() { | ||
if (params.validate) { | ||
return params.validate(); | ||
} | ||
} | ||
|
||
self.organisationNames = ko.observableArray(); | ||
|
||
self.selectOrganisation = function(item) { | ||
|
||
if (item && item.source) { | ||
self.editableOrganisation.organisationId(item.source.organisationId); | ||
self.editableOrganisation.organisationName(item.source.name); | ||
if (!self.editableOrganisation.name()) { | ||
self.editableOrganisation.name(item.source.name); | ||
} | ||
self.allowedNames(self.allowedNamesForOrganisation(item.source)); | ||
} | ||
else { | ||
self.editableOrganisation.organisationId(null); | ||
} | ||
|
||
} | ||
|
||
self.clearSelectedOrganisation = function() { | ||
$('#searchOrganisation').val(''); | ||
self.allowedNames([]); | ||
self.editableOrganisation.organisationId(null); | ||
self.editableOrganisation.name(''); | ||
self.editableOrganisation.description(''); | ||
self.editableOrganisation.fromDate(''); | ||
self.editableOrganisation.toDate(''); | ||
} | ||
|
||
self.editableOrganisation = new AssociatedOrg(); | ||
|
||
}, | ||
template: componentService.getTemplate('associated-orgs') | ||
}); |
101 changes: 101 additions & 0 deletions
101
grails-app/assets/components/template/associated-orgs.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
|
||
<div class="associatedOrgs mt-3"> | ||
Associated Organisations | ||
|
||
<div class=" pl-0 associated-org-list" data-bind="foreach:associatedOrgs"> | ||
|
||
<div class="actions"> | ||
<button class="btn btn-sm btn-container" data-bind="click:$parent.editAssociatedOrg"><i class="fa fa-edit"></i></button> | ||
<button class="btn btn-sm btn-container" data-bind="click:$parent.removeAssociatedOrg"><i class="fa fa-remove"></i></button> | ||
</div> | ||
<div> | ||
<!-- ko if: $data.organisationId() --> | ||
<a href="" data-bind="attr:{href:$parent.organisationViewUrl + '/' + $data.organisationId()}"> | ||
<span data-bind="text:name"></span> | ||
</a> | ||
<!-- /ko --> | ||
|
||
<!-- ko if:!$data.organisationId() --> | ||
<span data-bind="text:name"></span> | ||
<!-- /ko --> | ||
</div> | ||
<div> | ||
( <span data-bind="text:description"></span> | ||
<!-- ko if:fromDate --> | ||
<span> from <span data-bind="text:fromDate.formattedDate"></span></span> | ||
<!-- /ko --> | ||
<!-- ko if:toDate --> | ||
<span> to <span data-bind="text:toDate.formattedDate"></span></span> | ||
<!-- /ko --> | ||
) | ||
</div> | ||
|
||
</div> | ||
<div class="mb-3"> | ||
<button id="addAssociatedOrgButton" class="btn btn-sm" data-bind="click:addAssociatedOrg">Add Organisation</button> | ||
<input type="text" class="invisibleValidationHolder" name="invisibleValidationHolder" data-bind="jqueryValidationEngine:{namespace:validationNamespace, validationFunction:associatedOrgValidation}"> | ||
</div> | ||
|
||
</div> | ||
|
||
<!-- ko using:editableOrganisation --> | ||
<div id="add-or-edit-organisation" class="modal fade" tabindex="-1" role="dialog"> | ||
<div class="modal-dialog" role="document"> | ||
<div class="modal-content"> | ||
<div class="modal-header"> | ||
<h4 class="modal-title" id="title">Organisation relationship</h4> | ||
</div> | ||
|
||
|
||
<form class="modal-body"> | ||
<div class="form-group"> | ||
<label for="searchOrganisation">Search for an existing organisation</label> | ||
<div class="input-group input-append"> | ||
<input type="text" id="searchOrganisation" name="organisation-search" autocomplete="off" class="form-control form-control-sm" placeholder="Search organisations..." | ||
data-bind="enable:!organisationId(), elasticSearchAutocomplete:{url:$parent.organisationSearchUrl, value:'name', label:'name', result:$parent.selectOrganisation}"/> | ||
<span class="input-group-text"><i class="fa fa-remove" data-bind="click:$parent.clearSelectedOrganisation"></i></span> | ||
</div> | ||
</div> | ||
<!-- ko if:$parent.displayName --> | ||
<div class="form-group"> | ||
<label for="name-to-use" class="required">Organisation name as it appears on the project page (e.g. name used in contract)</label> | ||
|
||
<select class="form-control" id="name-to-use" data-bind="enable:organisationId(), value:name, options:$parent.allowedNames" | ||
data-validation-engine="validate[required]" data-prompt-position="topLeft"></select> | ||
</div> | ||
<!-- /ko --> | ||
<div class="form-group"> | ||
<label class="required" for="relationship-description">Relationship</label> | ||
<!-- ko if:$parent.relationshipTypes --> | ||
<select id="relationship-description" name="description" class="form-control form-control-sm" data-bind="enable:organisationId(), options:$parent.relationshipTypes, value:description"></select> | ||
<!-- /ko --> | ||
<!-- ko if:!$parent.relationshipTypes --> | ||
<input type="text" id="relationship-description" name="description" class="form-control form-control-sm" data-bind="enable:organisationId(), value:description"></input> | ||
<!-- /ko --> | ||
</div> | ||
<div class="form-group"> | ||
<label for="relationship-from-date">From date</label> | ||
<div class="input-group input-append"> | ||
<input id="relationship-from-date" name="relationship-from-date" autocomplete="off" class="form-control" data-bind="enable:organisationId(), datepicker:fromDate.date" type="text"> | ||
<span class="input-group-text open-datepicker"><i class="fa fa-th"></i></span> | ||
</div> | ||
</div> | ||
<div class="form-group"> | ||
<label for="relationship-to-date">To date</label> | ||
<div class="input-group input-append"> | ||
<input id="relationship-to-date" class="form-control" autocomplete="off" data-bind="enable:organisationId(), datepicker:toDate.date" name="to-date" type="text" | ||
data-validation-engine="validate[future[#relationship-from-date]]" data-prompt-position="topLeft"> | ||
<span class="input-group-text open-datepicker"><i class="fa fa-th"></i></span> | ||
</div> | ||
</div> | ||
</form> | ||
|
||
<div class="modal-footer"> | ||
<button type="button" class="btn btn-sm btn-success" name="save-org-changes" | ||
data-bind="enable:organisationId(), click:$parent.okPressed">OK</button> | ||
<button class="btn btn-sm btn-danger" data-bind="click:$parent.close">Cancel</button> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<!-- /ko --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.