Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scheme Label Editor & Reference Datatype Widget #169

Merged
merged 42 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
51ca818
make import flexible
johnatawnclementawn Dec 12, 2024
0a6e33b
Stub out reference dt widget rename from controlledlistitem
johnatawnclementawn Dec 18, 2024
b98ed49
Stub out label viewer #147
johnatawnclementawn Dec 19, 2024
c2093dd
Parse refdt options and pass to widget component #147
johnatawnclementawn Dec 30, 2024
6c10a1f
Get option labels to populate dropdown & align listitem type with til…
johnatawnclementawn Dec 31, 2024
9ff15fa
Update uri ref for select component reactivity #147
johnatawnclementawn Dec 31, 2024
310401c
Handle multiValue reference datatype in widget editor #147
johnatawnclementawn Jan 2, 2025
6b74f41
Use refdt widget in label editor #147
johnatawnclementawn Jan 2, 2025
abf06f7
nits #147
johnatawnclementawn Jan 2, 2025
e3c119d
Add resource instance nodes to scheme label form #147
johnatawnclementawn Jan 2, 2025
5d8c7c3
Add person_rdm slug and upgrade model to latest v8 requirements #147
johnatawnclementawn Jan 2, 2025
60536ab
pr feedback & readability improvements #147
johnatawnclementawn Jan 2, 2025
2a2b889
nit #147
johnatawnclementawn Jan 3, 2025
20227b0
Save / update scheme labels #147
johnatawnclementawn Jan 4, 2025
faae95c
creates date datatype after rebase #147 (#174)
chrabyrd Jan 6, 2025
1f6b076
nit #147
johnatawnclementawn Jan 6, 2025
4ea7d6c
Parse date value from primevue #147
johnatawnclementawn Jan 8, 2025
f067d49
Handle value updates for all node types #147
johnatawnclementawn Jan 8, 2025
be6d74e
Clean up refdt value ingestion #147
johnatawnclementawn Jan 8, 2025
0500832
Fix label values not updating between edit sessions and update save m…
johnatawnclementawn Jan 8, 2025
eb23d27
rm unnessecary assignment
johnatawnclementawn Jan 8, 2025
57348b8
fix labeleditor update #147
johnatawnclementawn Jan 8, 2025
f901175
nit #147
johnatawnclementawn Jan 8, 2025
c290ff6
Fix console warning about shallowRef
jacobtylerwalls Jan 8, 2025
d325db5
Fix reactivity of primeuve picker
jacobtylerwalls Jan 8, 2025
a3c7cb4
ensure metastring viewer is in view mode #147
johnatawnclementawn Jan 8, 2025
86f230e
Merge branch 'main' into jmc/147_scheme_label_editor
johnatawnclementawn Jan 8, 2025
c07c6ae
nit
johnatawnclementawn Jan 8, 2025
510f59c
Revert "Fix reactivity of primeuve picker"
johnatawnclementawn Jan 9, 2025
65f5e83
pr feedback #147
johnatawnclementawn Jan 10, 2025
e41c50f
Add form labels and passthru values for accessibility #147
johnatawnclementawn Jan 13, 2025
8ffb6c1
When creating new tile, update edit session #147
johnatawnclementawn Jan 13, 2025
557a2a0
nit #147
johnatawnclementawn Jan 14, 2025
f71bacb
Prevent multiple prefLabels in same language #147
johnatawnclementawn Jan 15, 2025
8418e8a
nit #147
johnatawnclementawn Jan 15, 2025
96dd5b2
Avoid hard coded fetching of reference dt options #147
johnatawnclementawn Jan 16, 2025
02a721e
naming nit #147
johnatawnclementawn Jan 16, 2025
600fe2f
Harden prefLabel check to prevent tile creation errors
jacobtylerwalls Jan 16, 2025
46e44f1
More informative failure (for now) if multiple prefLabel list items
jacobtylerwalls Jan 17, 2025
bff6057
Use useId()
jacobtylerwalls Jan 17, 2025
57ea8cc
Revert "Revert "Fix reactivity of primeuve picker""
jacobtylerwalls Jan 17, 2025
35a1237
Fix pt pass thru
jacobtylerwalls Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
266 changes: 173 additions & 93 deletions arches_lingo/pkg/graphs/resource_models/person_rdm_system.json

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions arches_lingo/serializers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from rest_framework.exceptions import ValidationError

from arches_references.models import ListItem

from arches.app.models.models import ResourceInstance, TileModel
from arches.app.models.serializers import ArchesModelSerializer, ArchesTileSerializer

Expand Down Expand Up @@ -49,6 +53,35 @@ class Meta:
root_node = "appellative_status"
fields = "__all__"

def validate(self, data):
data = super().validate(data)
graph_slug = self.Meta.graph_slug
PREF_LABEL_LIST_ITEM = ListItem.objects.get(list_item_values__value="prefLabel")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to catch MultipleObjectsReturned or otherwise define which list item wins.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed an update for this, a bit silly, but there are probably better things we can do in the future around identifying a list with a natural key (should name be unique, assuming it's not localized?)


if data:
new_label_language = data["appellative_status_ascribed_name_language"][0]
new_label_type = data["appellative_status_ascribed_relation"][0]

resource_instance_id = self.instance.resourceinstance.pk
resource_instance = self.instance.resourceinstance.__class__.as_model(
graph_slug, resource_ids=[resource_instance_id]
).get(pk=resource_instance_id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm looking into adding a developer convenience for this, either a method .enrich() and/or overwriting the .resourceinstance descriptor on the TileQuerySet so that it's a lazy getter that calls enrich() for you. 👀

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Not suggesting to block this PR on it.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobtylerwalls I swear this was working yesterday, but when I try to create a new label for an existing scheme self.instance is None. Would you be able to take a look at that in my absence?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I think you and I were only testing updates, not creates. I also added a little developer convenience for now.

current_labels = resource_instance.appellative_status

for label in current_labels:
label_language = label.appellative_status_ascribed_name_language[0]
label_type = label.appellative_status_ascribed_relation[0]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These fail with KeyError if not provided. If these fields are truly required at the node config level (seems like a model issue that they aren't) then the arches queryset layer that handles the tile validation logic will reject it. But since that layer is later, this layer needs to be a little more forgiving.

Unless!

We "override" the fields in this serializer to enforce that they're required at the outermost layer. Something like:

diff --git a/arches_lingo/serializers.py b/arches_lingo/serializers.py
index 1017492..db61b2b 100644
--- a/arches_lingo/serializers.py
+++ b/arches_lingo/serializers.py
@@ -1,3 +1,4 @@
+from rest_framework import serializers
 from rest_framework.exceptions import ValidationError
 
 from arches_references.models import ListItem
@@ -47,6 +48,10 @@ class SchemeLabelSerializer(ArchesModelSerializer):
 
 
 class SchemeLabelTileSerializer(ArchesTileSerializer):
+    # Get this from a mapping from datatypes to serializer fields
+    # then add required=True to fail faster
+    appellative_status_ascribed_name_language = serializers.JSONField(allow_null=True, required=True)
+
     class Meta:
         model = TileModel
         graph_slug = "scheme"

If we do that, then your business logic doesn't need to guard against missing values, because we fail before getting here (Looks like we need to improve the error toast to actually return the error message from the server keyed on field name instead of just "Bad Request".)

Nice to have some options here. I'm not convinced overriding the serializer field is better; it's probably easier to just fix your [0] 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a fix for this, but we probably want a dataclass or something to prevent this awkward double fallback.

if (
data["tileid"] != label.tileid
and new_label_type["uri"] == PREF_LABEL_LIST_ITEM.uri
and label_type["uri"] == PREF_LABEL_LIST_ITEM.uri
and label_language["uri"] == new_label_language["uri"]
):
raise ValidationError(
"A preferred label with the same language already exists for this scheme."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I localized this and borrowed the wording from arches-references to prevent creating a second translatable string.

)
return data


class SchemeNoteSerializer(ArchesModelSerializer):
class Meta:
Expand Down Expand Up @@ -88,3 +121,19 @@ class Meta:
graph_slug = "concept"
nodegroups = "__all__"
fields = "__all__"


class PersonRdmSystemSerializer(ArchesModelSerializer):
class Meta:
model = ResourceInstance
graph_slug = "person"
nodegroups = "__all__"
fields = "__all__"


class GroupRdmSystemSerializer(ArchesModelSerializer):
class Meta:
model = ResourceInstance
graph_slug = "group"
nodegroups = "__all__"
fields = "__all__"
68 changes: 66 additions & 2 deletions arches_lingo/src/arches_lingo/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import arches from "arches";
import Cookies from "js-cookie";

import type { SchemeInstance } from "@/arches_lingo/types";
import type { AppellativeStatus, SchemeInstance } from "@/arches_lingo/types";

function getToken() {
const token = Cookies.get("csrftoken");
Expand Down Expand Up @@ -53,6 +52,20 @@ export const fetchTextualWorkRdmSystemList = async () => {
return parsed;
};

export const fetchGroupRdmSystemList = async () => {
const response = await fetch(arches.urls.api_group_list);
const parsed = await response.json();
if (!response.ok) throw new Error(parsed.message || response.statusText);
return parsed;
};

export const fetchPersonRdmSystemList = async () => {
const response = await fetch(arches.urls.api_person_list);
const parsed = await response.json();
if (!response.ok) throw new Error(parsed.message || response.statusText);
return parsed;
};

export const fetchSchemeCreation = async (schemeId: string) => {
const response = await fetch(arches.urls.api_scheme_creation(schemeId));
const parsed = await response.json();
Expand All @@ -67,6 +80,26 @@ export const fetchSchemeLabel = async (schemeId: string) => {
return parsed;
};

export const createSchemeLabel = async (
schemeId: string,
appellative_status: AppellativeStatus,
) => {
const response = await fetch(arches.urls.api_scheme_label_list_create, {
method: "POST",
headers: {
"X-CSRFTOKEN": getToken(),
"Content-Type": "application/json",
},
body: JSON.stringify({
resourceinstance: schemeId,
...appellative_status,
}),
});
const parsed = await response.json();
if (!response.ok) throw new Error(parsed.message || response.statusText);
return parsed;
};

export const deleteSchemeLabelTile = async (
schemeId: string,
tileId: string,
Expand All @@ -87,6 +120,30 @@ export const deleteSchemeLabelTile = async (
}
};

export const updateSchemeLabel = async (
schemeId: string,
tileId: string,
appellative_status: AppellativeStatus,
) => {
const response = await fetch(
arches.urls.api_scheme_label_tile(schemeId, tileId),
{
method: "PATCH",
headers: {
"X-CSRFTOKEN": getToken(),
"Content-Type": "application/json",
},
body: JSON.stringify(appellative_status),
},
);
const parsed = await response.json();
if (!response.ok)
throw new Error(
parsed.non_field_errors || parsed.message || response.statusText,
);
return parsed;
};

export const fetchSchemeNotes = async (schemeId: string) => {
const response = await fetch(arches.urls.api_scheme_note(schemeId));
const parsed = await response.json();
Expand Down Expand Up @@ -193,3 +250,10 @@ export const fetchSchemes = async () => {
if (!response.ok) throw new Error(parsed.message || response.statusText);
return parsed;
};

export const fetchControlledListOptions = async (controlledListId: string) => {
const response = await fetch(arches.urls.controlled_list(controlledListId));
const parsed = await response.json();
if (!response.ok) throw new Error(parsed.message || response.statusText);
return parsed;
};

This file was deleted.

46 changes: 46 additions & 0 deletions arches_lingo/src/arches_lingo/components/generic/DateDatatype.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script setup lang="ts">
import DateDatatypeViewer from "@/arches_lingo/components/generic/date-datatype/DateDatatypeViewer.vue";
import DateDatatypeEditor from "@/arches_lingo/components/generic/date-datatype/DateDatatypeEditor.vue";

import { EDIT, VIEW } from "@/arches_lingo/constants.ts";

import type { DataComponentMode } from "@/arches_lingo/types.ts";

interface Props {
dateFormat?: string;
mode?: DataComponentMode;
value?: string;
ptAriaLabeledBy?: string;
}

withDefaults(defineProps<Props>(), {
dateFormat: "yy-mm-dd",
mode: VIEW,
value: "",
});

const emits = defineEmits(["update"]);

const onUpdate = (val: string) => {
emits("update", val);
};
</script>

<template>
<div>
<div v-if="mode === VIEW">
<DateDatatypeViewer
:date-format="dateFormat"
:value="value"
/>
</div>
<div v-if="mode === EDIT">
<DateDatatypeEditor
:date-format="dateFormat"
:value="value"
:pt-aria-labeled-by="ptAriaLabeledBy"
@update="onUpdate"
/>
</div>
</div>
</template>
Loading
Loading