Skip to content

Commit

Permalink
feat: restore search form from query session
Browse files Browse the repository at this point in the history
  • Loading branch information
tada5hi committed Nov 23, 2023
1 parent 3db2f20 commit 26ef756
Show file tree
Hide file tree
Showing 13 changed files with 307 additions and 69 deletions.
8 changes: 7 additions & 1 deletion packages/core/src/core/resource/record/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type {

export function createResourceRecordManager<
T extends ObjectLiteral = ObjectLiteral,
>(context: ResourceRecordManagerContext<T>) : ResourceRecordManagerOutput {
>(context: ResourceRecordManagerContext<T>) : ResourceRecordManagerOutput<T> {
const busy : Ref<boolean> = ref(false);
const data : Ref<T | undefined> = ref(undefined);
const error : Ref<Error | undefined> = ref(undefined);
Expand All @@ -25,6 +25,10 @@ export function createResourceRecordManager<
const load : ResourceRecordLoadFn = async () => {
if (busy.value) return;

if (context.data) {
return;
}

busy.value = true;

try {
Expand Down Expand Up @@ -82,6 +86,8 @@ export function createResourceRecordManager<
};

return {
data,
busy,
load,
render,
};
Expand Down
12 changes: 8 additions & 4 deletions packages/core/src/core/resource/record/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { Slots, VNodeChild } from 'vue';
import type { Ref, Slots, VNodeChild } from 'vue';
import type { ObjectLiteral } from '../../../types';
import type { ErrorCollectionSlotProps, ErrorSlotProps } from '../../error';
import type { ResourceSlotName } from '../constants';

export type ResourceRecordManagerLoadFn<
DATA extends ObjectLiteral = ObjectLiteral,
> = () => Promise<DATA>;
> = () => Promise<DATA | undefined>;

export type ResourceRecordManagerContext<
T extends ObjectLiteral = ObjectLiteral,
Expand All @@ -16,9 +16,13 @@ export type ResourceRecordManagerContext<
expose?: (exposed?: Record<string, any>) => void
};

export type ResourceRecordManagerOutput = {
export type ResourceRecordManagerOutput<
T extends ObjectLiteral = ObjectLiteral,
> = {
load: ResourceRecordLoadFn,
render: () => VNodeChild
render: () => VNodeChild,
data: Ref<T | undefined>,
busy: Ref<boolean>
};

export type ResourceRecordLoadFn = () => Promise<any>;
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/domains/patient/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export type PatientFilterVitalStatus = Coding<'alive' | 'deceased'>[];
* @see https://github.com/KohlbacherLab/dnpm-dip-service-base/blob/main/src/main/scala/de/dnpm/dip/service/query/PatientFilter.scala
*/
export type PatientFilter = {
gender: PatientFilterGender,
ageRange: PatientFilterAgeRange,
vitalStatus: PatientFilterVitalStatus
gender?: PatientFilterGender,
ageRange?: PatientFilterAgeRange,
vitalStatus?: PatientFilterVitalStatus
};

export type PatientFilterInput = {
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/domains/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ export type CollectionResponse<T> = {
};

export type CodeRecord<V extends string = string> = {
code: V
code: V,
display?: string
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,19 @@ export default defineComponent({
const isSubmitted = ref(true);
const reset = () => {
gender.value = props.availableFilters.gender.map((el) => el.code);
vitalStatus.value = props.availableFilters.vitalStatus.map((el) => el.code);
age.value = {
min: props.availableFilters.ageRange.min,
max: props.availableFilters.ageRange.max,
};
if (props.availableFilters.gender) {
gender.value = props.availableFilters.gender.map((el) => el.code);
}
if (props.availableFilters.vitalStatus) {
vitalStatus.value = props.availableFilters.vitalStatus.map((el) => el.code);
}
if (props.availableFilters.ageRange) {
age.value = {
min: props.availableFilters.ageRange.min,
max: props.availableFilters.ageRange.max,
};
}
genderChanged.value = false;
vitalStatusChanged.value = false;
Expand All @@ -58,6 +65,9 @@ export default defineComponent({
reset();
const handleAgeRangeChanged = (ctx: { min: number, max: number}) => {
if (!props.availableFilters.ageRange) {
return;
}
age.value.min = Math.round(ctx.min);
age.value.max = Math.round(ctx.max);
Expand All @@ -71,6 +81,10 @@ export default defineComponent({
};
watch(gender, (value) => {
if (!props.availableFilters.gender) {
return;
}
if (value.length !== props.availableFilters.gender.length) {
genderChanged.value = true;
isSubmitted.value = false;
Expand All @@ -94,6 +108,9 @@ export default defineComponent({
}, { deep: true });
watch(vitalStatus, (value) => {
if (!props.availableFilters.vitalStatus) {
return;
}
if (value.length !== props.availableFilters.vitalStatus.length) {
vitalStatusChanged.value = true;
isSubmitted.value = false;
Expand Down Expand Up @@ -126,12 +143,14 @@ export default defineComponent({
if (ageChanged.value) {
data.ageRange = {};
if (age.value.min !== props.availableFilters.ageRange.min) {
data.ageRange.min = age.value.min;
}
if (props.availableFilters.ageRange) {
if (age.value.min !== props.availableFilters.ageRange.min) {
data.ageRange.min = age.value.min;
}
if (age.value.max !== props.availableFilters.ageRange.max) {
data.ageRange.max = age.value.max;
if (age.value.max !== props.availableFilters.ageRange.max) {
data.ageRange.max = age.value.max;
}
}
}
Expand Down Expand Up @@ -168,7 +187,10 @@ export default defineComponent({
</script>
<template>
<div class="entity-card">
<div class="mb-3">
<div
v-if="availableFilters.gender"
class="mb-3"
>
<h6><i class="fas fa-transgender-alt" /> Geschlecht</h6>

<div>
Expand All @@ -187,7 +209,10 @@ export default defineComponent({
</template>
</div>
</div>
<div class="mb-3">
<div
v-if="availableFilters.vitalStatus"
class="mb-3"
>
<h6><i class="fas fa-heartbeat" /> Vital Status</h6>

<div>
Expand All @@ -206,7 +231,10 @@ export default defineComponent({
</template>
</div>
</div>
<div class="mb-3">
<div
v-if="availableFilters.ageRange"
class="mb-3"
>
<h6><i class="fas fa-users" /> Alter <small class="text-muted">({{ age.min }} - {{ age.max }})</small></h6>

<div class="mt-3">
Expand Down
127 changes: 107 additions & 20 deletions packages/rare-diseases/src/runtime/components/core/SearchForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ import type {
} from '@dnpm-dip/core';
import type { FormSelectOption } from '@vue-layout/form-controls';
import { VCFormGroup, VCFormInput } from '@vue-layout/form-controls';
import type { PropType } from 'vue';
import { defineComponent, reactive, ref } from 'vue';
import { CodeSystemEntity, ValueSetEntity } from '@dnpm-dip/core';
import { CodeSystemEntity, ValueSetEntity, createResourceRecordManager } from '@dnpm-dip/core';
import { useRDAPIClient } from '#imports';
import type { RDQueryCriteria, RDQueryCriteriaScopeValue } from '../../domains';
import type {
RDQueryCriteria,
RDQueryCriteriaVariant,
RDQuerySession,
RDVariantCriteria,
} from '../../domains';
import FormSelectSearch from '../utility/FormSelectSearch.vue';
import Tags from '../utility/Tags.vue';
import CollectionTransform from '../utility/CollectionTransform.vue';
Expand All @@ -22,11 +28,79 @@ export default defineComponent({
CodeSystemEntity,
ValueSetEntity,
},
emits: ['failed', 'created'],
props: {
entity: {
type: Object as PropType<RDQuerySession>,
},
entityId: {
type: String,
},
},
emits: ['failed', 'created', 'updated'],
async setup(props, { emit }) {
const apiClient = useRDAPIClient();
const manager = createResourceRecordManager<RDQuerySession>({
data: props.entity,
async load() {
if (props.entityId) {
return apiClient.query.getOne(props.entityId);
}
return undefined;
},
});
const categories = ref<FormSelectOption[]>([]);
const hpoTerms = ref<FormSelectOption[]>([]);
const variants = reactive<RDQueryCriteriaVariant<string>>({
gene: '',
cDNAChange: '',
gDNAChange: '',
proteinChange: '',
});
const parse = () => {
if (!manager.data.value || !manager.data.value.criteria) {
return;
}
const criteria = manager.data.value?.criteria;
if (
criteria?.variants &&
criteria.variants.length > 0
) {
const keys = Object.keys(criteria.variants[0]) as RDVariantCriteria[];
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
variants[key] = (criteria.variants[0] as RDQueryCriteriaVariant)[key]?.code;
}
}
if (criteria?.hpoTerms) {
for (let i = 0; i < criteria.hpoTerms.length; i++) {
hpoTerms.value.push({
id: criteria.hpoTerms[i].code,
value: criteria.hpoTerms[i].display || criteria.hpoTerms[i].code,
});
}
}
if (criteria?.diagnoses) {
for (let i = 0; i < criteria.diagnoses.length; i++) {
categories.value.push({
id: criteria.diagnoses[i].code,
value: criteria.diagnoses[i].display || criteria.diagnoses[i].code,
});
}
}
};
Promise.resolve()
.then(() => manager.load())
.then(() => parse());
const selectCategory = (item: FormSelectOption) => {
const index = categories.value.findIndex((el) => el.id === item.id);
if (index === -1) {
Expand All @@ -45,24 +119,19 @@ export default defineComponent({
}
};
const variants = reactive({
gene: '',
cDNAChange: '',
gDNAChange: '',
proteinChange: '',
});
const submit = async (mode: `${QueryRequestMode}`) => {
if (manager.busy.value) return;
const apiClient = useRDAPIClient();
manager.busy.value = true;
const submit = async (mode: `${QueryRequestMode}`) => {
const criteria : RDQueryCriteria = {};
const keys = Object.keys(variants);
if (keys.length > 0) {
let isValid = false;
const group : Record<string, CodeRecord> = {};
for (let i = 0; i < keys.length; i++) {
const code = variants[keys[i] as keyof typeof variants];
if (code.length > 0) {
if (code && code.length > 0) {
group[keys[i]] = {
code,
};
Expand Down Expand Up @@ -96,18 +165,33 @@ export default defineComponent({
}
try {
const data = await apiClient.query.submit({
criteria,
mode: {
code: mode,
},
});
emit('created', data);
let data : RDQuerySession;
if (manager.data.value) {
data = await apiClient.query.update(manager.data.value.id, {
criteria,
mode: {
code: mode,
},
});
emit('created', data);
} else {
data = await apiClient.query.submit({
criteria,
mode: {
code: mode,
},
});
emit('created', data);
}
} catch (e) {
if (e instanceof Error) {
emit('failed', e);
}
} finally {
manager.busy.value = false;
}
};
Expand All @@ -122,6 +206,7 @@ export default defineComponent({
});
return {
busy: manager.busy,
hpoTerms,
categories,
Expand Down Expand Up @@ -290,6 +375,7 @@ export default defineComponent({
<div class="row">
<div class="col">
<button
:disabled="busy"
type="button"
class="btn btn-sm btn-block btn-dark"
@click.prevent="submit('local')"
Expand All @@ -299,6 +385,7 @@ export default defineComponent({
</div>
<div class="col">
<button
:disabled="busy"
type="button"
class="btn btn-sm btn-block btn-dark"
@click.prevent="submit('federated')"
Expand Down
Loading

0 comments on commit 26ef756

Please sign in to comment.