Skip to content

Commit

Permalink
Merge branch 'dev/8.0.x' into 10540_importing_models_delayed_loading
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeGriniezakis authored Feb 17, 2025
2 parents 2957c75 + 31ff7cb commit 1befd58
Show file tree
Hide file tree
Showing 70 changed files with 4,065 additions and 1,648 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Issue reports are encouraged! [Please read this article](http://polite.technolog
* [Report a Bug](https://github.com/archesproject/arches/issues/new?template=bug.md)
* [File a Feature Ticket](https://github.com/archesproject/arches/issues/new?template=feature.md)

[Version 7.6.3 release notes](https://github.com/archesproject/arches/blob/dev/7.6.x/releases/7.6.3.md)
[Version 7.6.6 release notes](https://github.com/archesproject/arches/blob/dev/7.6.x/releases/7.6.6.md)

#### Quick Install

Expand Down
4 changes: 3 additions & 1 deletion arches/app/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

IntegrityCheckDescriptions = {
1005: "Nodes with ontologies found in graphs without ontologies",
1012: "Node Groups without matching nodes",
1012: "Node Groups without contained nodes",
1013: "Node Groups without a grouping node",
1014: "Publication missing for language",
}

Expand All @@ -12,6 +13,7 @@
class IntegrityCheck(Enum):
NODE_HAS_ONTOLOGY_GRAPH_DOES_NOT = 1005
NODELESS_NODE_GROUP = 1012
NODEGROUP_WITHOUT_GROUPING_NODE = 1013
PUBLICATION_MISSING_FOR_LANGUAGE = 1014

def __str__(self):
Expand Down
7 changes: 5 additions & 2 deletions arches/app/etl_modules/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.db import connection
from django.http import HttpRequest
from django.utils.translation import gettext as _
from django.urls import reverse, resolve
from django.urls import reverse, resolve, get_script_prefix
from arches.app.models.system_settings import settings
from arches.app.utils.index_database import index_resources_by_transaction
import logging
Expand Down Expand Up @@ -187,7 +187,10 @@ def get_resourceids_from_search_url(search_url, user=None):
params = parse_qs(urlsplit(search_url).query)
for k, v in params.items():
request.GET.__setitem__(k, v[0])
func, args, kwargs = resolve(reverse("search_results"))
search_results_path = reverse("search_results")
if search_results_path.startswith(get_script_prefix()):
search_results_path = search_results_path.replace(get_script_prefix(), "/")
func, args, kwargs = resolve(search_results_path)
kwargs["request"] = request
response = func(*args, **kwargs)
results = json.loads(response.content)["results"]["hits"]["hits"]
Expand Down
5 changes: 5 additions & 0 deletions arches/app/media/css/arches.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10176,6 +10176,11 @@ table.table.dataTable {
font-size: 1.4rem;
}

.copy-geojson-url-message {
padding: 2px;
font-size: 1.2rem;
}

.search-type-btn-popup.relative:hover {
background: #fff;
color: #25476A;
Expand Down
17 changes: 7 additions & 10 deletions arches/app/media/js/bindings/select2-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ define([
var newOption = new Option(data.text, data.id, false, false);
// Append it to the select
$(el).append(newOption);
}
}
});
// maintain the current selection after adding new dropdown options
$(el).val(currentSelection).trigger('change');
Expand All @@ -92,13 +92,13 @@ define([

$(document).ready(function() {
$(el).selectWoo(select2Config);

if (value) {
value.extend({ rateLimit: 100 });
// initialize the dropdown with the value
$(el).val(value());
$(el).trigger('change.select2');
$(el).trigger('change.select2');

// update the dropdown if something else changes the value
const valueSubscription = value.subscribe(function(newVal) {
//console.log(newVal);
Expand All @@ -119,21 +119,18 @@ define([
},300);
});


$(el).on("change", function(e) {
let val = $(el).val();
if (val === "") {
val = null;
}
value(val);
});

$(el).on("select2:opening", function() {
if (select2Config.clickBubble) {
$(el).parent().trigger('click');
}
});

if (typeof select2Config.onSelect === 'function') {
$(el).on("select2:selecting", function(e) {
select2Config.onSelect(e.params.args.data);
Expand Down
2 changes: 1 addition & 1 deletion arches/app/media/js/reports/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ define([
if (imgs.length === 0) {
imgs = [{
src: arches.urls.media + 'img/photo_missing.png',
alt: ''
alt: arches.translations.imageNotAvailable,
}];
}
return imgs;
Expand Down
1 change: 1 addition & 0 deletions arches/app/media/js/viewmodels/graph-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ define([
$.ajax({
type: "POST",
url: arches.urls.graph_settings(self.graph.graphid()),
contentType: 'application/json',
data: self.jsonData()})
.done(function(response) {
self.jsonCache(self.jsonData());
Expand Down
22 changes: 13 additions & 9 deletions arches/app/media/js/viewmodels/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,17 @@ define([
var id = data.resourceinstanceid;
const userid = ko.unwrap(self.userid);
data.showFilterByFeatureButton = !!params.search;
data.showEditButton = false;
data.sendFeatureToMapFilter = mapPopupProvider.sendFeatureToMapFilter.bind(mapPopupProvider);
data.showFilterByFeature = mapPopupProvider.showFilterByFeature.bind(mapPopupProvider);
const descriptionProperties = ['displayname', 'graph_name', 'map_popup', 'geometries'];
const setEditButtonVisibility = function(data)
{
const isFeatureEditable = self.canEdit &&
ko.unwrap(data.permissions)?.users_without_edit_perm?.includes(userid) === false ||
ko.unwrap(data.permissions)?.principal_user?.includes(userid) ||
ko.unwrap(data.permissions)?.users_edit?.includes(userid);
data.showEditButton(isFeatureEditable);
}
if (id) {
if (!self.resourceLookup[id]){
data = _.defaults(data, {
Expand All @@ -358,21 +365,16 @@ define([
'map_popup': '',
'geometries': [],
'feature': feature,
'showEditButton': ko.observable(false)
});

if (data.permissions) {
try {
data.permissions = JSON.parse(ko.unwrap(data.permissions));
} catch (err) {
data.permissions = koMapping.toJS(ko.unwrap(data.permissions));
}

const hasInstanceEditPermission = data.permissions.users_without_edit_perm?.includes(userid) === false ||
data.permissions.principal_user?.includes(userid) ||
data.permissions.users_edit?.includes(userid);

if (self.canEdit && hasInstanceEditPermission) {
data.showEditButton = true;
}
setEditButtonVisibility(data);
}
descriptionProperties.forEach(prop => data[prop] = ko.observable(data[prop]));
data.reportURL = arches.urls.resource_report;
Expand All @@ -381,6 +383,8 @@ define([
$.get(arches.urls.resource_descriptors + id, function(data) {
data.loading = false;
descriptionProperties.forEach(prop => self.resourceLookup[id][prop](data[prop]));
self.resourceLookup[id].permissions = data["permissions"];
setEditButtonVisibility(self.resourceLookup[id]);
});
}
self.resourceLookup[id].feature = feature;
Expand Down
10 changes: 10 additions & 0 deletions arches/app/media/js/views/components/search/search-export.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ define([
this.downloadPending = ko.observable(false);
this.hasResourceTypeFilter = ko.observable(!!sharedStateObject.query()['resource-type-filter']);
this.exportSystemValues = ko.observable(false);
this.copyGeojsonText = ko.observable("");
this.showCopyText = ko.observable(false);

this.query.subscribe(function(val) {
if (val['resource-type-filter']) {
Expand Down Expand Up @@ -64,6 +66,14 @@ define([
}
});

this.copyGeojsonUrlText = function(){
self.copyGeojsonText("Geojson url copied to clipboard.")
self.showCopyText(true);
window.setTimeout(function(){
self.showCopyText(false);
}, 6000);
};

this.getExportData = function(){
var payload = ko.unwrap(this.query);
self.downloadPending(true);
Expand Down
2 changes: 1 addition & 1 deletion arches/app/media/js/views/rdm/modals/manage-parent-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ define(['jquery', 'backbone', 'arches', 'views/concept-search', 'models/concept'

save: function(){
var self = this;
if (this.conceptsearch.searchbox.val() !== ''){
if (this.conceptsearch.searchbox.val()){
var parentConcept = new ConceptModel({
id: this.conceptsearch.searchbox.val(),
relationshiptype: this.relationshiptype.val()
Expand Down
30 changes: 21 additions & 9 deletions arches/app/models/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,9 @@ def flatten_tree(tree, node_id_list=[]):
if is_collector:
old_nodegroup_id = node.nodegroup_id
node.nodegroup = models.NodeGroup(
pk=node.pk, cardinality=node.nodegroup.cardinality
pk=node.pk,
cardinality=node.nodegroup.cardinality,
grouping_node=node,
)
if old_nodegroup_id not in nodegroup_map:
nodegroup_map[old_nodegroup_id] = node.nodegroup_id
Expand Down Expand Up @@ -1284,7 +1286,8 @@ def update_node(self, node):
new_node.fieldname = node["fieldname"]
self.populate_null_nodegroups()

# new_node will always have a nodegroup id even it if was set to None becuase populate_null_nodegroups
# new_node will always have a nodegroup id even if if was set to None
# because populate_null_nodegroups
# will populate the nodegroup id with the parent nodegroup
# add/remove a card if a nodegroup was added/removed
if new_node.nodegroup_id != old_node.nodegroup_id:
Expand Down Expand Up @@ -1317,7 +1320,7 @@ def update_node(self, node):

def delete_node(self, node=None):
"""
deletes a node and all if it's children from a graph
deletes a node and all of its children from a graph
Arguments:
node -- a node id or Node model to delete from the graph
Expand Down Expand Up @@ -1830,20 +1833,28 @@ def get_or_create_nodegroup(self, nodegroupid, nodegroups_list=[]):
"""
get a nodegroup from an id by first looking through the nodes and cards associated with this graph.
if not found then get the nodegroup instance from the database, otherwise return a new instance of a nodegroup
This is also the method responsible for setting the grouping_node_id
on the nodegroup when the first (collector) node is created.
Keyword Arguments
nodegroupid -- return a nodegroup with this id
nodegroups_list -- list of nodegroups from which to filter
"""

found = None
for nodegroup in nodegroups_list or self.get_nodegroups():
if str(nodegroup.nodegroupid) == str(nodegroupid):
return nodegroup
try:
return models.NodeGroup.objects.get(pk=nodegroupid)
except models.NodeGroup.DoesNotExist:
return models.NodeGroup(pk=nodegroupid)
found = nodegroup
break
else:
try:
found = models.NodeGroup.objects.get(pk=nodegroupid)
except models.NodeGroup.DoesNotExist:
found = models.NodeGroup(pk=nodegroupid, grouping_node_id=nodegroupid)

found.grouping_node_id = found.nodegroupid
return found

def get_root_nodegroup(self):
"""
Expand Down Expand Up @@ -2436,6 +2447,7 @@ def _update_source_nodegroup_hierarchy(nodegroup):

source_nodegroup.cardinality = nodegroup.cardinality
source_nodegroup.legacygroupid = nodegroup.legacygroupid
source_nodegroup.grouping_node_id = source_nodegroup.pk

if nodegroup.parentnodegroup_id:
nodegroup_parent_node = models.Node.objects.get(
Expand Down Expand Up @@ -2480,7 +2492,7 @@ def _update_source_nodegroup_hierarchy(nodegroup):
# graph ( the graph mapped to `self` ); we iterate over the item attributes and map
# them to source item. If the item does not have a `source_identifier` attribute, it
# has been newly created; we update the `graph_id` to match the source graph. We are
# not saving in this block so updates can accur in any order.
# not saving in this block so updates can occur in any order.
for future_widget in list(editable_future_graph.widgets.values()):
source_widget = future_widget.source_identifier

Expand Down
2 changes: 1 addition & 1 deletion arches/app/models/migrations/10999_update_principaluser.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Migration(migrations.Migration):
reverse_sql="select 1;",
),
migrations.RunSQL(
sql="update resource_instances a set principaluser_id = b.userid::integer from (select userid, resourceinstanceid from edit_log where edittype = 'create' and userid != '' and userid is not null)b where a.resourceinstanceid::text = b.resourceinstanceid",
sql="update resource_instances a set principaluser_id = b.userid::integer from (select userid, resourceinstanceid from edit_log where edittype = 'create' and userid != '' and userid is not null)b where a.resourceinstanceid::text = b.resourceinstanceid and b.userid::integer in (select id from auth_user)",
reverse_sql="select 1;",
),
# Moved from 10799_geojsongeometry_featureid in 7.6.2
Expand Down
69 changes: 69 additions & 0 deletions arches/app/models/migrations/11613_nodegroup_grouping_node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Generated by Django 5.1.3 on 2024-11-19 09:29

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("models", "11408_loadstaging_sortorder"),
]

def add_grouping_node(apps, schema_editor):
NodeGroup = apps.get_model("models", "NodeGroup")
nodegroups_with_nodes = NodeGroup.objects.filter(node__gt=0).distinct()
for nodegroup in nodegroups_with_nodes:
nodegroup.grouping_node_id = nodegroup.pk
NodeGroup.objects.bulk_update(nodegroups_with_nodes, ["grouping_node_id"])

PublishedGraph = apps.get_model("models", "PublishedGraph")
published_graphs = PublishedGraph.objects.all()
for published_graph in published_graphs:
for nodegroup_dict in published_graph.serialized_graph["nodegroups"]:
nodegroup_dict["grouping_node_id"] = nodegroup_dict["nodegroupid"]
PublishedGraph.objects.bulk_update(published_graphs, ["serialized_graph"])

def remove_grouping_node(apps, schema_editor):
PublishedGraph = apps.get_model("models", "PublishedGraph")
published_graphs = PublishedGraph.objects.all()
for published_graph in published_graphs:
for nodegroup_dict in published_graph.serialized_graph["nodegroups"]:
nodegroup_dict.pop("grouping_node_id", None)
PublishedGraph.objects.bulk_update(published_graphs, ["serialized_graph"])

operations = [
migrations.AddField(
model_name="nodegroup",
name="grouping_node",
field=models.OneToOneField(
blank=True,
db_column="groupingnodeid",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="grouping_node_nodegroup",
to="models.node",
),
),
migrations.AlterField(
model_name="nodegroup",
name="cardinality",
field=models.CharField(
blank=True, choices=[("1", "1"), ("n", "n")], default="1", max_length=1
),
),
migrations.AlterField(
model_name="nodegroup",
name="parentnodegroup",
field=models.ForeignKey(
blank=True,
db_column="parentnodegroupid",
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="children",
related_query_name="child",
to="models.nodegroup",
),
),
migrations.RunPython(add_grouping_node, remove_grouping_node),
]
Loading

0 comments on commit 1befd58

Please sign in to comment.