Skip to content

Commit

Permalink
Adds note editor (#177)
Browse files Browse the repository at this point in the history
  • Loading branch information
aarongundel committed Jan 18, 2025
1 parent ed3b0ca commit 8895e83
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 7 deletions.
47 changes: 46 additions & 1 deletion arches_lingo/src/arches_lingo/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import arches from "arches";
import Cookies from "js-cookie";
import type { AppellativeStatus, SchemeInstance } from "@/arches_lingo/types";
import type {
AppellativeStatus,
SchemeInstance,
SchemeStatement,
} from "@/arches_lingo/types";

function getToken() {
const token = Cookies.get("csrftoken");
Expand Down Expand Up @@ -100,6 +104,26 @@ export const createSchemeLabel = async (
return parsed;
};

export const createSchemeNote = async (
schemeId: string,
statement: SchemeStatement,
) => {
const response = await fetch(arches.urls.api_scheme_note_create, {
method: "POST",
headers: {
"X-CSRFTOKEN": getToken(),
"Content-Type": "application/json",
},
body: JSON.stringify({
resourceinstance: schemeId,
...statement,
}),
});
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 Down Expand Up @@ -151,6 +175,27 @@ export const fetchSchemeNotes = async (schemeId: string) => {
return parsed;
};

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

export const deleteSchemeNoteTile = async (
schemeId: string,
tileId: string,
Expand Down
318 changes: 318 additions & 0 deletions arches_lingo/src/arches_lingo/components/generic/NoteEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
<script setup lang="ts">
import { computed, inject, onMounted, ref, toRaw, toRef, type Ref } from "vue";
import Button from "primevue/button";
import { useGettext } from "vue3-gettext";
import { useRoute, useRouter } from "vue-router";
import { useToast } from "primevue/usetoast";
import {
createScheme,
createSchemeNote,
fetchControlledListOptions,
fetchGroupRdmSystemList,
fetchPersonRdmSystemList,
fetchTextualWorkRdmSystemList,
updateSchemeNote,
} from "@/arches_lingo/api.ts";
import DateDatatype from "@/arches_lingo/components/generic/DateDatatype.vue";
import NonLocalizedString from "@/arches_lingo/components/generic/NonLocalizedString.vue";
import ReferenceDatatype from "@/arches_lingo/components/generic/ReferenceDatatype.vue";
import ResourceInstanceRelationships from "@/arches_lingo/components/generic/ResourceInstanceRelationships.vue";
import {
EDIT,
ERROR,
EVENT_TYPES_CONTROLLED_LIST,
LABEL_CONTROLLED_LIST,
LANGUAGE_CONTROLLED_LIST,
METATYPES_CONTROLLED_LIST,
NEW,
selectedLanguageKey,
STATUSES_CONTROLLED_LIST,
} from "@/arches_lingo/constants.ts";
import type {
ControlledListItem,
ControlledListItemResult,
ResourceInstanceReference,
ResourceInstanceResult,
SchemeInstance,
SchemeStatement,
} from "@/arches_lingo/types.ts";
import type { Language } from "@/arches_vue_utils/types.ts";
const emit = defineEmits(["update"]);
const toast = useToast();
const route = useRoute();
const router = useRouter();
const selectedLanguage = inject(selectedLanguageKey) as Ref<Language>;
const { $gettext } = useGettext();
const props = withDefaults(
defineProps<{
value?: SchemeStatement;
}>(),
{
value: () => ({}) as SchemeStatement,
},
);
const valueRef = toRef(props, "value");
const formValue = computed({
get: () => valueRef.value,
set: (newVal: SchemeStatement) => {
valueRef.value = newVal;
},
});
onMounted(async () => {
initializeSelectOptions();
});
const languageOptions = ref<ControlledListItem[]>([]);
const typeOptions = ref<ControlledListItem[]>([]);
const statusOptions = ref<ControlledListItem[]>([]);
const metatypeOptions = ref<ControlledListItem[]>([]);
const eventTypeOptions = ref<ControlledListItem[]>([]);
const groupAndPersonOptions = ref<ResourceInstanceReference[]>();
const textualWorkOptions = ref<ResourceInstanceReference[]>();
function onUpdateString(node: keyof SchemeStatement, val: string) {
(formValue.value[node] as unknown) = toRaw(val);
}
function onUpdateReferenceDatatype(
node: keyof SchemeStatement,
val: ControlledListItem[],
) {
(formValue.value[node] as unknown) = val.map((item) => toRaw(item));
}
function onUpdateResourceInstance(
node: keyof SchemeStatement,
val: string[],
options: ResourceInstanceReference[],
) {
if (val.length > 0) {
const selectedOptions = options.filter((option) =>
val.includes(option.resourceId),
);
(formValue.value[node] as unknown) = selectedOptions;
}
}
async function save() {
try {
if (route.params.id === NEW) {
const newSchemeInstance: SchemeInstance = {
statement: [toRaw(formValue.value)],
};
const updated = await createScheme(newSchemeInstance);
await router.push({
name: "scheme",
params: { id: updated.resourceinstanceid },
});
} else if (!formValue.value.tileid) {
const schemeStatement: SchemeStatement = await createSchemeNote(
route.params.id as string,
{ ...formValue.value },
);
valueRef.value = schemeStatement;
emit("update", schemeStatement.tileid);
return;
} else {
await updateSchemeNote(
route.params.id as string,
formValue.value.tileid,
{ ...formValue.value },
);
}
emit("update");
} catch (error) {
toast.add({
severity: ERROR,
summary: $gettext("Error saving scheme"),
detail: (error as Error).message,
});
}
}
async function getControlledListOptions(
listId: string,
): Promise<ControlledListItem[]> {
const parsed = await fetchControlledListOptions(listId);
const options = parsed.items.map(
(item: ControlledListItemResult): ControlledListItem => ({
list_id: item.list_id,
uri: item.uri,
labels: item.values,
}),
);
return options;
}
async function getResourceInstanceOptions(
fetchOptions: () => Promise<ResourceInstanceResult[]>,
): Promise<ResourceInstanceReference[]> {
const options = await fetchOptions();
const results = options.map((option: ResourceInstanceResult) => {
const result: ResourceInstanceReference = {
display_value: option.descriptors[selectedLanguage.value.code].name,
resourceId: option.resourceinstanceid,
ontologyProperty: "ac41d9be-79db-4256-b368-2f4559cfbe55",
inverseOntologyProperty: "ac41d9be-79db-4256-b368-2f4559cfbe55",
};
return result;
});
return results;
}
async function initializeSelectOptions() {
const [languageOpts, typeOpts, statusOpts, metatypeOpts, eventTypeOpts] =
await Promise.all([
getControlledListOptions(LANGUAGE_CONTROLLED_LIST),
getControlledListOptions(LABEL_CONTROLLED_LIST),
getControlledListOptions(STATUSES_CONTROLLED_LIST),
getControlledListOptions(METATYPES_CONTROLLED_LIST),
getControlledListOptions(EVENT_TYPES_CONTROLLED_LIST),
]);
languageOptions.value = languageOpts;
typeOptions.value = typeOpts;
statusOptions.value = statusOpts;
metatypeOptions.value = metatypeOpts;
eventTypeOptions.value = eventTypeOpts;
groupAndPersonOptions.value = await getResourceInstanceOptions(
fetchGroupRdmSystemList,
);
groupAndPersonOptions.value = [
...(groupAndPersonOptions.value || []),
...(await getResourceInstanceOptions(fetchPersonRdmSystemList)),
];
textualWorkOptions.value = await getResourceInstanceOptions(
fetchTextualWorkRdmSystemList,
);
}
</script>

<template>
<!-- Statement: string -->
<label for="">{{ $gettext("Statement") }}</label>
<NonLocalizedString
:value="formValue?.statement_content_n1 ?? ''"
:mode="EDIT"
@update="(val) => onUpdateString('statement_content_n1', val)"
/>
<!-- Statement Language: reference datatype -->
<label for="">{{ $gettext("Statement Language") }}</label>
<ReferenceDatatype
:value="formValue?.statement_language_n1"
:mode="EDIT"
:multi-value="false"
:options="languageOptions"
@update="
(val) => onUpdateReferenceDatatype('statement_language_n1', val)
"
/>
<!-- Statement Type: reference datatype -->
<label for="">{{ $gettext("Statement Type") }}</label>
<ReferenceDatatype
:value="formValue?.statement_type_n1"
:mode="EDIT"
:multi-value="false"
:options="typeOptions"
@update="(val) => onUpdateReferenceDatatype('statement_type_n1', val)"
/>

<!-- Statement Status Metatype: reference datatype -->
<label for="">{{ $gettext("Statement Metatype") }}</label>
<ReferenceDatatype
:value="formValue?.statement_type_metatype_n1"
:mode="EDIT"
:multi-value="false"
:options="metatypeOptions"
@update="
(val) =>
onUpdateReferenceDatatype('statement_type_metatype_n1', val)
"
/>

<!-- Statement Temporal Validity Start: date -->
<label for="">{{ $gettext("Label Temporal Validity Start") }}</label>
<DateDatatype
:value="
formValue?.statement_data_assignment_timespan_begin_of_the_begin
"
:mode="EDIT"
@update="
(val) =>
onUpdateString(
'statement_data_assignment_timespan_begin_of_the_begin',
val,
)
"
/>

<!-- Statement Temporal Validity End: date -->
<label for="">{{ $gettext("Label Temporal Validity End") }}</label>
<DateDatatype
:value="formValue?.statement_data_assignment_timespan_end_of_the_end"
:mode="EDIT"
@update="
(val) =>
onUpdateString(
'statement_data_assignment_timespan_end_of_the_end',
val,
)
"
/>

<!-- Contributor: resource instance -->
<label for="">{{ $gettext("Contributor") }}</label>
<ResourceInstanceRelationships
:value="formValue?.statement_data_assignment_actor"
:mode="EDIT"
:options="groupAndPersonOptions"
@update="
(val) =>
onUpdateResourceInstance(
'statement_data_assignment_actor',
val,
groupAndPersonOptions ?? [],
)
"
/>
<!-- Sources: resource instance -->
<label for="">{{ $gettext("Sources") }}</label>
<ResourceInstanceRelationships
:value="formValue?.statement_data_assignment_object_used"
:mode="EDIT"
:options="textualWorkOptions"
@update="
(val) =>
onUpdateResourceInstance(
'statement_data_assignment_object_used',
val,
textualWorkOptions ?? [],
)
"
/>
<!-- Warrant Type: reference datatype -->
<label for="">{{ $gettext("Warrant Type") }}</label>
<ReferenceDatatype
:value="formValue?.statement_data_assignment_type"
:mode="EDIT"
:multi-value="false"
:options="eventTypeOptions"
@update="
(val) =>
onUpdateReferenceDatatype('statement_data_assignment_type', val)
"
/>
<Button
:label="$gettext('Update')"
@click="save"
></Button>
</template>
Loading

0 comments on commit 8895e83

Please sign in to comment.