From dc6755d6f968ed53f02a9afc23a6f4dd43ee1a2d Mon Sep 17 00:00:00 2001 From: tada5hi Date: Tue, 29 Oct 2024 10:27:56 +0100 Subject: [PATCH] feat: reorganized query filter store --- .../components/core/query/QueryFilterBox.vue | 2 +- .../core/src/stores/query-filter/helper.ts | 36 ++++++++++++ .../core/src/stores/query-filter/index.ts | 1 + .../core/src/stores/query-filter/module.ts | 57 ++++++++++--------- .../core/src/stores/query-filter/types.ts | 8 ++- .../components/core/MMutationTabGroup.vue | 6 +- .../core/MQuerySummaryTumorDiagnostics.vue | 12 ++-- .../MQueryCriteriaSummary.vue | 4 +- .../MQueryCriteriaSummaryBox.vue | 6 +- .../MQueryPatientMatch.vue | 28 +++++++-- .../MQueryPatientMatches.ts | 9 ++- .../core/{ => search}/MSearchCNVForm.vue | 9 ++- .../core/{ => search}/MSearchForm.vue | 13 ++++- .../core/{ => search}/MSearchFusionForm.vue | 9 ++- .../{ => search}/MSearchMedicationForm.vue | 0 .../core/{ => search}/MSearchSNVForm.vue | 9 ++- packages/mtb/src/runtime/pages/index.vue | 2 +- .../src/runtime/pages/query/[id]/index.vue | 8 ++- .../pages/query/[id]/index/patients.vue | 4 +- packages/portal/core/navigation/module.ts | 2 +- 20 files changed, 163 insertions(+), 62 deletions(-) create mode 100644 packages/core/src/stores/query-filter/helper.ts rename packages/mtb/src/runtime/components/core/{ => query-criteria}/MQueryCriteriaSummary.vue (99%) rename packages/mtb/src/runtime/components/core/{ => query-criteria}/MQueryCriteriaSummaryBox.vue (96%) rename packages/mtb/src/runtime/components/core/{ => query-patient}/MQueryPatientMatch.vue (85%) rename packages/mtb/src/runtime/components/core/{ => query-patient}/MQueryPatientMatches.ts (82%) rename packages/mtb/src/runtime/components/core/{ => search}/MSearchCNVForm.vue (96%) rename packages/mtb/src/runtime/components/core/{ => search}/MSearchForm.vue (98%) rename packages/mtb/src/runtime/components/core/{ => search}/MSearchFusionForm.vue (96%) rename packages/mtb/src/runtime/components/core/{ => search}/MSearchMedicationForm.vue (100%) rename packages/mtb/src/runtime/components/core/{ => search}/MSearchSNVForm.vue (95%) diff --git a/packages/core/src/components/core/query/QueryFilterBox.vue b/packages/core/src/components/core/query/QueryFilterBox.vue index 75f96f68..d986501e 100644 --- a/packages/core/src/components/core/query/QueryFilterBox.vue +++ b/packages/core/src/components/core/query/QueryFilterBox.vue @@ -9,7 +9,7 @@ import { defineComponent, ref } from 'vue'; export default defineComponent({ setup() { - const extended = ref(false); + const extended = ref(true); const toggleExtended = () => { extended.value = !extended.value; diff --git a/packages/core/src/stores/query-filter/helper.ts b/packages/core/src/stores/query-filter/helper.ts new file mode 100644 index 00000000..7e304b1c --- /dev/null +++ b/packages/core/src/stores/query-filter/helper.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024. + * Author Peter Placzek (tada5hi) + * For the full copyright and license information, + * view the LICENSE file that was distributed with this source code. + */ + +import { serializeCoding } from '../../domains'; +import type { QueryFilterGroup, QueryFilters } from './types'; + +export function buildQueryFilterURLValue(items: QueryFilterGroup[]) { + const output = items + .map((group) => group + .map((el) => serializeCoding(el)) + .join('+')); + + if (output.length > 0) { + return output.join(','); + } + + return undefined; +} + +export function buildQueryFiltersURLRecord(items: QueryFilters) { + const output : Record = {}; + + const keys = Object.keys(items); + for (let i = 0; i < keys.length; i++) { + const value = buildQueryFilterURLValue(items[keys[i]]); + if (value) { + output[keys[i]] = value; + } + } + + return output; +} diff --git a/packages/core/src/stores/query-filter/index.ts b/packages/core/src/stores/query-filter/index.ts index 2c9f5533..8f67af47 100644 --- a/packages/core/src/stores/query-filter/index.ts +++ b/packages/core/src/stores/query-filter/index.ts @@ -5,6 +5,7 @@ * view the LICENSE file that was distributed with this source code. */ +export * from './helper'; export * from './install'; export * from './module'; export * from './singleton'; diff --git a/packages/core/src/stores/query-filter/module.ts b/packages/core/src/stores/query-filter/module.ts index 89f04a3e..7b3f3fea 100644 --- a/packages/core/src/stores/query-filter/module.ts +++ b/packages/core/src/stores/query-filter/module.ts @@ -5,11 +5,13 @@ * view the LICENSE file that was distributed with this source code. */ +import { isEqual } from 'smob'; import { ref } from 'vue'; import type { Coding } from '../../domains'; -import { serializeCoding } from '../../domains'; import { QueryEventBusEventName } from '../../services'; import type { StoreCreateOptions } from '../types'; +import { buildQueryFiltersURLRecord } from './helper'; +import type { QueryFilterGroup, QueryFilterGroupInput, QueryFilters } from './types'; const toCoding = (input: string | Coding) : Coding => { if (typeof input === 'string') { @@ -21,15 +23,31 @@ const toCoding = (input: string | Coding) : Coding => { return input; }; -type FilterGroupInput = string | Coding | string[] | Coding[]; +export function createQueryFilterStore(ctx: StoreCreateOptions) { + const items = ref({}); -type FilterGroup = Coding[]; -type Filters = Record; + const hasGroup = (key: string, input: QueryFilterGroupInput) => { + if (typeof items.value[key] === 'undefined' || items.value[key].length === 0) { + return false; + } -export function createQueryFilterStore(ctx: StoreCreateOptions) { - const items = ref({}); + let data : Coding[]; + if (Array.isArray(input)) { + data = input.map((el) => toCoding(el)); + } else { + data = [toCoding(input)]; + } - const addGroup = (key: string, input: FilterGroupInput) => { + for (let i = 0; i < items.value[key].length; i++) { + if (isEqual(items.value[key][i], data)) { + return true; + } + } + + return false; + }; + + const addGroup = (key: string, input: QueryFilterGroupInput) => { let data : Coding[]; if (Array.isArray(input)) { data = input.map((el) => toCoding(el)); @@ -48,7 +66,7 @@ export function createQueryFilterStore(ctx: StoreCreateOptions) { items.value[key] = []; }; - const set = (key: string, input: FilterGroupInput[]) => { + const set = (key: string, input: QueryFilterGroupInput[]) => { reset(key); for (let i = 0; i < input.length; i++) { @@ -58,7 +76,7 @@ export function createQueryFilterStore(ctx: StoreCreateOptions) { ctx.queryEventBus.emit(QueryEventBusEventName.FILTER_UPDATED, key); }; - const get = (key: string) : FilterGroup[] => items.value[key] || []; + const get = (key: string) : QueryFilterGroup[] => items.value[key] || []; const resetAll = () => { items.value = {}; @@ -68,25 +86,12 @@ export function createQueryFilterStore(ctx: StoreCreateOptions) { ctx.queryEventBus.emit(QueryEventBusEventName.FILTERS_COMMITED); }; - const buildURLRecord = () => { - const output : Record = {}; - - const keys = Object.keys(items.value); - for (let i = 0; i < keys.length; i++) { - const groups : string[] = items.value[keys[i]] - .map((group) => group - .map((el) => serializeCoding(el)) - .join('+')); - - if (groups.length > 0) { - output[keys[i]] = groups.join(','); - } - } - - return output; - }; + const buildURLRecord = () => buildQueryFiltersURLRecord(items.value); return { + hasGroup, + addGroup, + items, buildURLRecord, diff --git a/packages/core/src/stores/query-filter/types.ts b/packages/core/src/stores/query-filter/types.ts index bb4fd04d..8e5dc61c 100644 --- a/packages/core/src/stores/query-filter/types.ts +++ b/packages/core/src/stores/query-filter/types.ts @@ -10,8 +10,10 @@ import type { StoreDefinition as BaseStoreDefinition, Pinia, _ExtractActionsFromSetupStore, - _ExtractGettersFromSetupStore, _ExtractStateFromSetupStore, + _ExtractGettersFromSetupStore, + _ExtractStateFromSetupStore, } from 'pinia'; +import type { Coding } from '../../domains'; import type { createQueryFilterStore } from './module'; @@ -33,3 +35,7 @@ _ExtractActionsFromSetupStore export type QueryFilterStoreInstallOptions = { pinia?: Pinia }; + +export type QueryFilterGroupInput = string | Coding | string[] | Coding[]; +export type QueryFilterGroup = Coding[]; +export type QueryFilters = Record; diff --git a/packages/mtb/src/runtime/components/core/MMutationTabGroup.vue b/packages/mtb/src/runtime/components/core/MMutationTabGroup.vue index d653b542..1caaeb4a 100644 --- a/packages/mtb/src/runtime/components/core/MMutationTabGroup.vue +++ b/packages/mtb/src/runtime/components/core/MMutationTabGroup.vue @@ -8,9 +8,9 @@ import { defineComponent, markRaw, ref, toRef, } from 'vue'; import { FormMutationType, type MutationDefinition } from '../../domains'; -import MSearchCNVForm from './MSearchCNVForm.vue'; -import MSearchFusionForm from './MSearchFusionForm.vue'; -import MSearchSNVForm from './MSearchSNVForm.vue'; +import MSearchCNVForm from './search/MSearchCNVForm.vue'; +import MSearchFusionForm from './search/MSearchFusionForm.vue'; +import MSearchSNVForm from './search/MSearchSNVForm.vue'; export default defineComponent({ components: { VCFormSelect }, diff --git a/packages/mtb/src/runtime/components/core/MQuerySummaryTumorDiagnostics.vue b/packages/mtb/src/runtime/components/core/MQuerySummaryTumorDiagnostics.vue index 6380def1..0628bb61 100644 --- a/packages/mtb/src/runtime/components/core/MQuerySummaryTumorDiagnostics.vue +++ b/packages/mtb/src/runtime/components/core/MQuerySummaryTumorDiagnostics.vue @@ -1,7 +1,10 @@