@platforma-sdk/ui-vue 1.40.4 → 1.40.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +60 -33
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +18 -0
- package/dist/AgGridVue/useAgGridOptions.js +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts +1 -4
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +150 -167
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgRowCount.vue.js +1 -1
- package/dist/components/PlAgDataTable/sources/table-source-v2.d.ts +2 -2
- package/dist/components/PlAgDataTable/sources/table-source-v2.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-source-v2.js +114 -109
- package/dist/components/PlAgDataTable/sources/table-source-v2.js.map +1 -1
- package/dist/components/PlAgDataTable/types.d.ts +27 -43
- package/dist/components/PlAgDataTable/types.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/types.js +32 -43
- package/dist/components/PlAgDataTable/types.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue.js +6 -6
- package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue.js +1 -1
- package/dist/components/PlAgRowNumHeader.vue.js +1 -1
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue.d.ts +17 -0
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue.d.ts.map +1 -0
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue.js +10 -0
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue.js.map +1 -0
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js +99 -0
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js.map +1 -0
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue3.js +15 -0
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue3.js.map +1 -0
- package/dist/components/PlAnnotations/components/DynamicForm.vue.d.ts +25 -0
- package/dist/components/PlAnnotations/components/DynamicForm.vue.d.ts.map +1 -0
- package/dist/components/PlAnnotations/components/DynamicForm.vue.js +10 -0
- package/dist/components/PlAnnotations/components/DynamicForm.vue.js.map +1 -0
- package/dist/components/PlAnnotations/components/DynamicForm.vue2.js +110 -0
- package/dist/components/PlAnnotations/components/DynamicForm.vue2.js.map +1 -0
- package/dist/components/PlAnnotations/components/DynamicForm.vue3.js +9 -0
- package/dist/components/PlAnnotations/components/DynamicForm.vue3.js.map +1 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.vue.d.ts +20 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.vue.d.ts.map +1 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.vue.js +10 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.vue.js.map +1 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js +124 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js.map +1 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.vue3.js +13 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.vue3.js.map +1 -0
- package/dist/components/PlAnnotations/components/PlAnnotationCreateDialog.vue.d.ts +19 -0
- package/dist/components/PlAnnotations/components/PlAnnotationCreateDialog.vue.d.ts.map +1 -0
- package/dist/components/PlAnnotations/components/PlAnnotationCreateDialog.vue.js +78 -0
- package/dist/components/PlAnnotations/components/PlAnnotationCreateDialog.vue.js.map +1 -0
- package/dist/components/PlAnnotations/components/PlAnnotationCreateDialog.vue2.js +5 -0
- package/dist/components/PlAnnotations/components/PlAnnotationCreateDialog.vue2.js.map +1 -0
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue.d.ts +23 -0
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue.d.ts.map +1 -0
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue.js +10 -0
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue.js.map +1 -0
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js +97 -0
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js.map +1 -0
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue3.js +13 -0
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue3.js.map +1 -0
- package/dist/components/PlAnnotations/index.d.ts +2 -0
- package/dist/components/PlAnnotations/index.d.ts.map +1 -0
- package/dist/components/PlAnnotations/types.d.ts +8 -0
- package/dist/components/PlAnnotations/types.d.ts.map +1 -0
- package/dist/components/PlAnnotations/utils.d.ts +6 -0
- package/dist/components/PlAnnotations/utils.d.ts.map +1 -0
- package/dist/components/PlAnnotations/utils.js +29 -0
- package/dist/components/PlAnnotations/utils.js.map +1 -0
- package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue.js +8 -8
- package/dist/components/PlMultiSequenceAlignment/Toolbar.vue2.js +5 -5
- package/dist/components/PlMultiSequenceAlignment/data.js +62 -62
- package/dist/components/PlTableFilters/PlTableAddFilterV2.vue.js +8 -8
- package/dist/defineApp.js +6 -6
- package/dist/lib/model/common/dist/index.js.map +1 -1
- package/dist/lib/ui/uikit/dist/components/DataTable/TableComponent.vue.js +22 -22
- package/dist/lib/ui/uikit/dist/components/PlAccordion/{ExpandTransition.vue2.js → ExpandTransition.vue.js} +1 -1
- package/dist/lib/ui/uikit/dist/components/PlAccordion/ExpandTransition.vue.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlAccordion/PlAccordionSection.vue2.js +1 -1
- package/dist/lib/ui/uikit/dist/components/PlAutocomplete/PlAutocomplete.vue.js +1 -1
- package/dist/lib/ui/uikit/dist/components/PlBtnGhost/PlBtnGhost.vue.js +3 -3
- package/dist/lib/ui/uikit/dist/components/PlConfirmDialog.vue.js +63 -0
- package/dist/lib/ui/uikit/dist/components/PlConfirmDialog.vue.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlDialogModal/PlDialogModal.vue.js +37 -37
- package/dist/lib/ui/uikit/dist/components/PlDialogModal/PlDialogModal.vue.js.map +1 -1
- package/dist/lib/ui/uikit/dist/components/PlDropdown/PlDropdown.vue.js +1 -1
- package/dist/lib/ui/uikit/dist/components/PlDropdownLegacy/PlDropdownLegacy.vue.js +1 -1
- package/dist/lib/ui/uikit/dist/components/PlDropdownMulti/PlDropdownMulti.vue.js +1 -1
- package/dist/lib/ui/uikit/dist/components/PlEditableTitle/PlEditableTitle.vue.js +42 -38
- package/dist/lib/ui/uikit/dist/components/PlEditableTitle/PlEditableTitle.vue.js.map +1 -1
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue2.js +20 -16
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementList.vue2.js.map +1 -1
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue.js +2 -2
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue2.js +17 -16
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue2.js.map +1 -1
- package/dist/lib/ui/uikit/dist/components/PlElementList/PlElementListItem.vue3.js +27 -27
- package/dist/lib/ui/uikit/dist/components/PlElementList/utils.js +7 -6
- package/dist/lib/ui/uikit/dist/components/PlElementList/utils.js.map +1 -1
- package/dist/lib/ui/uikit/dist/components/PlFileDialog/PlFileDialog.vue.js +19 -19
- package/dist/lib/ui/uikit/dist/components/PlFileInput/PlFileInput.vue.js +1 -1
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarGroup.vue.js +10 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarGroup.vue.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarGroup.vue2.js +21 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarGroup.vue2.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarGroup.vue3.js +20 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarGroup.vue3.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarItem.vue.js +10 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarItem.vue.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarItem.vue2.js +39 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarItem.vue2.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarItem.vue3.js +26 -0
- package/dist/lib/ui/uikit/dist/components/PlSidebar/PlSidebarItem.vue3.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/PlPureSlideModal.vue.js +116 -0
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/PlPureSlideModal.vue.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/PlSlideModal.vue.js +7 -128
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/PlSlideModal.vue.js.map +1 -1
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/PlSlideModal.vue2.js +56 -0
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/PlSlideModal.vue2.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/PlSlideModal.vue3.js +18 -0
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/PlSlideModal.vue3.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/props.js +10 -0
- package/dist/lib/ui/uikit/dist/components/PlSlideModal/props.js.map +1 -0
- package/dist/lib/ui/uikit/dist/components/PlTextArea/PlTextArea.vue.js +1 -1
- package/dist/lib/ui/uikit/dist/components/PlTextField/PlTextField.vue.js +1 -1
- package/dist/lib/ui/uikit/dist/composition/useConfirm.js +23 -0
- package/dist/lib/ui/uikit/dist/composition/useConfirm.js.map +1 -0
- package/dist/lib/ui/uikit/dist/generated/components/svg/images/{SvgRequired.vue.js → SvgRequired.vue2.js} +1 -1
- package/dist/lib/ui/uikit/dist/generated/components/svg/images/SvgRequired.vue2.js.map +1 -0
- package/dist/lib/ui/uikit/dist/index.js +92 -88
- package/dist/lib/ui/uikit/dist/index.js.map +1 -1
- package/dist/lib/ui/uikit/dist/lib/model/common/dist/index.js +5 -5
- package/dist/lib/ui/uikit/dist/sdk/model/dist/index.js +42 -42
- package/dist/lib/ui/uikit/dist/sdk/model/dist/index.js.map +1 -1
- package/dist/lib/util/helpers/dist/index.js +60 -50
- package/dist/lib/util/helpers/dist/index.js.map +1 -1
- package/dist/lib.d.ts +1 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +261 -251
- package/dist/lib.js.map +1 -1
- package/dist/plugins/Monetization/MonetizationSidebar.vue.js +9 -9
- package/dist/sdk/model/dist/index.js +926 -539
- package/dist/sdk/model/dist/index.js.map +1 -1
- package/package.json +6 -8
- package/src/components/PlAgDataTable/PlAgDataTableV2.vue +20 -74
- package/src/components/PlAgDataTable/sources/table-source-v2.ts +29 -29
- package/src/components/PlAgDataTable/types.ts +42 -70
- package/src/components/PlAnnotations/components/AnnotationsSidebar.vue +103 -0
- package/src/components/PlAnnotations/components/DynamicForm.vue +144 -0
- package/src/components/PlAnnotations/components/FilterSidebar.vue +143 -0
- package/src/components/PlAnnotations/components/PlAnnotationCreateDialog.vue +64 -0
- package/src/components/PlAnnotations/components/PlAnnotationsModal.vue +114 -0
- package/src/components/PlAnnotations/index.ts +1 -0
- package/src/components/PlAnnotations/types.ts +9 -0
- package/src/components/PlAnnotations/utils.ts +25 -0
- package/src/lib.ts +2 -0
- package/dist/lib/ui/uikit/dist/components/PlAccordion/ExpandTransition.vue2.js.map +0 -1
- package/dist/lib/ui/uikit/dist/generated/components/svg/images/SvgRequired.vue.js.map +0 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<script setup lang="ts" generic="T extends FilterUi = FilterUi">
|
|
2
|
+
import { computed, watch } from 'vue';
|
|
3
|
+
import type { FilterUi, SUniversalPColumnId, TypeFieldRecord } from '@platforma-sdk/model';
|
|
4
|
+
import type { FilterUiType } from '@platforma-sdk/model';
|
|
5
|
+
import { isNil } from '@milaboratories/helpers';
|
|
6
|
+
import { PlTextField, PlDropdown, PlNumberField, PlCheckbox } from '@milaboratories/uikit';
|
|
7
|
+
import { getFilterUiTypeOptions, getFilterUiMetadata } from '@platforma-sdk/model';
|
|
8
|
+
import type { SimplifiedUniversalPColumnEntry } from '../types';
|
|
9
|
+
|
|
10
|
+
type ObjectEntries<T, K extends keyof T = keyof T> = [K, T[K]][];
|
|
11
|
+
|
|
12
|
+
const formData = defineModel<T>({ default: () => ({}) });
|
|
13
|
+
|
|
14
|
+
const props = defineProps<{
|
|
15
|
+
columns: SimplifiedUniversalPColumnEntry[];
|
|
16
|
+
formMetadata: TypeFieldRecord<T>;
|
|
17
|
+
}>();
|
|
18
|
+
|
|
19
|
+
const columnSpecRef = computed(() => {
|
|
20
|
+
const value = formData.value;
|
|
21
|
+
if ('column' in value) {
|
|
22
|
+
return props.columns.find((c) => c.id === value.column)?.obj;
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const typeMetadataRef = computed(() => {
|
|
28
|
+
const value = formData.value;
|
|
29
|
+
if (value.type && typeof value.type === 'string') {
|
|
30
|
+
return getFilterUiMetadata(value.type);
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const filterUiTypeOptions = computed(() => {
|
|
36
|
+
return getFilterUiTypeOptions(columnSpecRef.value);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const firstColumnsOptions = computed(() => props.columns.map((c) => ({ label: c.label, value: c.id })));
|
|
40
|
+
const secondColumnOptions = computed(() => {
|
|
41
|
+
const typeMetadata = typeMetadataRef.value;
|
|
42
|
+
const columnSpec = columnSpecRef.value;
|
|
43
|
+
if (typeMetadata && columnSpec) {
|
|
44
|
+
return props.columns.filter((c) => typeMetadata.supportedFor(columnSpec, c.obj)).map((c) => ({
|
|
45
|
+
label: c.label,
|
|
46
|
+
value: c.id,
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
return [];
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const setFieldValue = <K extends keyof T>(fieldName: K, value: T[K]) => {
|
|
53
|
+
formData.value[fieldName] = value;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
watch(() => props.formMetadata, (newForm) => {
|
|
57
|
+
for (const [fieldName, field] of Object.entries(newForm) as ObjectEntries<typeof newForm>) {
|
|
58
|
+
if (formData.value[fieldName] === undefined) {
|
|
59
|
+
const value = field.defaultValue();
|
|
60
|
+
if (!isNil(value)) {
|
|
61
|
+
formData.value[fieldName] = value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{ immediate: true, deep: true },
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<template>
|
|
72
|
+
<div v-if="formMetadata" :class="$style.form">
|
|
73
|
+
<template v-for="(field, fieldName) in formMetadata" :key="fieldName">
|
|
74
|
+
<template v-if="field.fieldType === 'form'">
|
|
75
|
+
<!-- TODO: Nested Form not described in FilterUi, we need to define it later. Even more in type it don't possible situations -->
|
|
76
|
+
<DynamicForm
|
|
77
|
+
v-if="'form' in field"
|
|
78
|
+
:model-value="formData[fieldName] as any"
|
|
79
|
+
:form-metadata="field.form as any"
|
|
80
|
+
:columns="props.columns"
|
|
81
|
+
@update:model-value="setFieldValue(fieldName, $event as T[keyof T])"
|
|
82
|
+
/>
|
|
83
|
+
</template>
|
|
84
|
+
<template v-else-if="field.fieldType === 'FilterUiType'">
|
|
85
|
+
<PlDropdown
|
|
86
|
+
:model-value="formData[fieldName] as FilterUiType"
|
|
87
|
+
:label="field.label ?? fieldName"
|
|
88
|
+
:options="filterUiTypeOptions"
|
|
89
|
+
@update:model-value="setFieldValue(fieldName, $event as T[keyof T])"
|
|
90
|
+
/>
|
|
91
|
+
</template>
|
|
92
|
+
<template v-else-if="field.fieldType === 'string'">
|
|
93
|
+
<PlTextField
|
|
94
|
+
:model-value="formData[fieldName] as string"
|
|
95
|
+
:label="field.label ?? fieldName"
|
|
96
|
+
@update:model-value="setFieldValue(fieldName, $event as T[keyof T])"
|
|
97
|
+
/>
|
|
98
|
+
</template>
|
|
99
|
+
<template v-else-if="field.fieldType === 'SUniversalPColumnId'">
|
|
100
|
+
<PlDropdown
|
|
101
|
+
:model-value="formData[fieldName] as SUniversalPColumnId"
|
|
102
|
+
:label="field.label ?? fieldName"
|
|
103
|
+
:options="fieldName === 'column' ? firstColumnsOptions : secondColumnOptions"
|
|
104
|
+
@update:model-value="setFieldValue(fieldName, $event as T[keyof T])"
|
|
105
|
+
/>
|
|
106
|
+
</template>
|
|
107
|
+
<template v-else-if="field.fieldType === 'number'">
|
|
108
|
+
<PlNumberField
|
|
109
|
+
:model-value="formData[fieldName] as number"
|
|
110
|
+
:label="field.label ?? fieldName"
|
|
111
|
+
@update:model-value="setFieldValue(fieldName, $event as T[keyof T])"
|
|
112
|
+
/>
|
|
113
|
+
</template>
|
|
114
|
+
<template v-else-if="field.fieldType === 'number?'">
|
|
115
|
+
<PlNumberField
|
|
116
|
+
:model-value="formData[fieldName] as (undefined | number)"
|
|
117
|
+
:label="field.label ?? fieldName"
|
|
118
|
+
:clearable="true"
|
|
119
|
+
@update:model-value="setFieldValue(fieldName, $event as T[keyof T])"
|
|
120
|
+
/>
|
|
121
|
+
</template>
|
|
122
|
+
<template v-else-if="field.fieldType === 'boolean' || field.fieldType === 'boolean?'">
|
|
123
|
+
<PlCheckbox
|
|
124
|
+
:model-value="Boolean(formData[fieldName])"
|
|
125
|
+
:label="field.label ?? fieldName"
|
|
126
|
+
@update:model-value="setFieldValue(fieldName, $event as T[keyof T])"
|
|
127
|
+
>
|
|
128
|
+
{{ field.label ?? fieldName }}
|
|
129
|
+
</PlCheckbox>
|
|
130
|
+
</template>
|
|
131
|
+
<template v-else>
|
|
132
|
+
<pre>TODO:{{ field.fieldType }}</pre>
|
|
133
|
+
</template>
|
|
134
|
+
</template>
|
|
135
|
+
</div>
|
|
136
|
+
</template>
|
|
137
|
+
|
|
138
|
+
<style module>
|
|
139
|
+
.form {
|
|
140
|
+
display: flex;
|
|
141
|
+
flex-direction: column;
|
|
142
|
+
gap: 12px;
|
|
143
|
+
}
|
|
144
|
+
</style>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { isNil, randomInt } from '@milaboratories/helpers';
|
|
3
|
+
import {
|
|
4
|
+
PlBtnSecondary,
|
|
5
|
+
PlEditableTitle,
|
|
6
|
+
PlElementList,
|
|
7
|
+
PlSidebarItem,
|
|
8
|
+
} from '@milaboratories/uikit';
|
|
9
|
+
import type { AnnotationStepUi, FilterUi, PObjectId, SUniversalPColumnId } from '@platforma-sdk/model';
|
|
10
|
+
import { getFilterUiMetadata } from '@platforma-sdk/model';
|
|
11
|
+
import type { SimplifiedUniversalPColumnEntry } from '../types';
|
|
12
|
+
import { createDefaultFilterMetadata } from '../utils';
|
|
13
|
+
import DynamicForm from './DynamicForm.vue';
|
|
14
|
+
|
|
15
|
+
// Models
|
|
16
|
+
const step = defineModel<AnnotationStepUi>('step', { required: true });
|
|
17
|
+
// Props
|
|
18
|
+
const props = defineProps<{
|
|
19
|
+
columns: SimplifiedUniversalPColumnEntry[];
|
|
20
|
+
hasSelectedColumns: boolean;
|
|
21
|
+
getValuesForSelectedColumns: () => Promise<undefined | { columnId: PObjectId; values: string[] }>;
|
|
22
|
+
}>();
|
|
23
|
+
// Actions
|
|
24
|
+
const addFilterPlaceholder = () => {
|
|
25
|
+
step.value.filter.filters.push({
|
|
26
|
+
id: randomInt(),
|
|
27
|
+
isExpanded: true,
|
|
28
|
+
type: undefined,
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
async function addFilterFromSelected() {
|
|
33
|
+
const data = await props.getValuesForSelectedColumns();
|
|
34
|
+
if (!data || data.values.length === 0) return;
|
|
35
|
+
|
|
36
|
+
const { columnId, values } = data;
|
|
37
|
+
const shortReminder = values.slice(0, 3).join(', ') + (values.length > 3 ? ` and ${values.length - 3} more` : '');
|
|
38
|
+
|
|
39
|
+
step.value.filter.filters.push({
|
|
40
|
+
id: randomInt(),
|
|
41
|
+
name: `Selected list (${shortReminder})`,
|
|
42
|
+
isExpanded: false,
|
|
43
|
+
type: 'or',
|
|
44
|
+
filters: values.map((value) => ({
|
|
45
|
+
type: 'patternEquals',
|
|
46
|
+
column: columnId as SUniversalPColumnId,
|
|
47
|
+
value,
|
|
48
|
+
})),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Getters
|
|
53
|
+
const getColumnLabel = (filter: FilterUi) => {
|
|
54
|
+
if (!isNil(filter.name)) return filter.name;
|
|
55
|
+
return props.columns
|
|
56
|
+
.find((c) => 'column' in filter ? c.id === filter.column : false)?.label
|
|
57
|
+
?? filter.type;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const getFormMetadata = (filter: FilterUi) => {
|
|
61
|
+
return !isNil(filter.type) ? getFilterUiMetadata(filter.type).form : createDefaultFilterMetadata();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const getFilterValues = (filter: FilterUi) => {
|
|
65
|
+
if (filter.type === 'or' || filter.type === 'and') {
|
|
66
|
+
return filter.filters.map((f) => 'value' in f && !isNil(f.value) ? f.value : null).filter((v) => !isNil(v)).join (', ');
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
};
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<template>
|
|
73
|
+
<PlSidebarItem v-if="step">
|
|
74
|
+
<template #header-content>
|
|
75
|
+
<PlEditableTitle
|
|
76
|
+
:key="step.id"
|
|
77
|
+
v-model="step.label"
|
|
78
|
+
:max-length="40"
|
|
79
|
+
max-width="600px"
|
|
80
|
+
placeholder="Annotation Name"
|
|
81
|
+
:autofocus="step.label.length === 0"
|
|
82
|
+
/>
|
|
83
|
+
</template>
|
|
84
|
+
<template #body-content>
|
|
85
|
+
<div :class="$style.root">
|
|
86
|
+
<div :class="$style.actions">
|
|
87
|
+
<PlBtnSecondary style="width: 100%;" icon="add" @click="addFilterPlaceholder">
|
|
88
|
+
Filter
|
|
89
|
+
</PlBtnSecondary>
|
|
90
|
+
<PlBtnSecondary style="width: 100%;" icon="add" :disabled="!props.hasSelectedColumns" @click="addFilterFromSelected">
|
|
91
|
+
From selection
|
|
92
|
+
</PlBtnSecondary>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<span :class="$style.tip">Lower annotations override the ones above. Rearrange them by dragging.</span>
|
|
96
|
+
|
|
97
|
+
<PlElementList
|
|
98
|
+
v-model:items="step.filter.filters"
|
|
99
|
+
:get-item-key="(item) => item.id!"
|
|
100
|
+
:is-expanded="(item) => Boolean(item.isExpanded)"
|
|
101
|
+
:on-expand="(item) => item.isExpanded = !Boolean(item.isExpanded)"
|
|
102
|
+
>
|
|
103
|
+
<template #item-title="{ item }">
|
|
104
|
+
{{ getColumnLabel(item) }}
|
|
105
|
+
</template>
|
|
106
|
+
<template #item-content="{ item, index }">
|
|
107
|
+
<template v-if="item.type !== 'or' && item.type !== 'and'">
|
|
108
|
+
<DynamicForm
|
|
109
|
+
v-model="step.filter.filters[index]"
|
|
110
|
+
:form-metadata="getFormMetadata(item)"
|
|
111
|
+
:columns="props.columns"
|
|
112
|
+
/>
|
|
113
|
+
</template>
|
|
114
|
+
<template v-else>
|
|
115
|
+
<div>{{ getFilterValues(item) }}</div>
|
|
116
|
+
</template>
|
|
117
|
+
</template>
|
|
118
|
+
</PlElementList>
|
|
119
|
+
</div>
|
|
120
|
+
</template>
|
|
121
|
+
</PlSidebarItem>
|
|
122
|
+
</template>
|
|
123
|
+
|
|
124
|
+
<style lang="scss" module>
|
|
125
|
+
@use '@milaboratories/uikit/styles/variables' as *;
|
|
126
|
+
|
|
127
|
+
.root {
|
|
128
|
+
display: flex;
|
|
129
|
+
flex-direction: column;
|
|
130
|
+
gap: 12px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.actions {
|
|
134
|
+
display: flex;
|
|
135
|
+
flex-direction: row;
|
|
136
|
+
gap: 12px;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.tip {
|
|
140
|
+
margin-top: 12px;
|
|
141
|
+
color: var(--txt-03);
|
|
142
|
+
}
|
|
143
|
+
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SimpleOption } from '@milaboratories/uikit';
|
|
3
|
+
import { PlBtnGhost, PlBtnPrimary, PlDialogModal, PlRadioGroup, PlTextField } from '@milaboratories/uikit';
|
|
4
|
+
import type { AnnotationMode } from '@platforma-sdk/model';
|
|
5
|
+
import { computed, ref } from 'vue';
|
|
6
|
+
|
|
7
|
+
// Models
|
|
8
|
+
const opened = defineModel<boolean>({ required: true });
|
|
9
|
+
// Emits
|
|
10
|
+
const emits = defineEmits<{
|
|
11
|
+
(e: 'submit', props: { type: 'byClonotype' | 'bySampleAndClonotype'; name: string }): void;
|
|
12
|
+
}>();
|
|
13
|
+
|
|
14
|
+
const annotationSchemaTypes = [
|
|
15
|
+
{ label: 'Global', value: 'byClonotype' },
|
|
16
|
+
{ label: 'Per sample', value: 'bySampleAndClonotype' },
|
|
17
|
+
] satisfies SimpleOption<AnnotationMode>[];
|
|
18
|
+
|
|
19
|
+
const modalState = ref<{
|
|
20
|
+
type: 'byClonotype' | 'bySampleAndClonotype';
|
|
21
|
+
name: string;
|
|
22
|
+
}>({
|
|
23
|
+
type: 'byClonotype',
|
|
24
|
+
name: '',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const isValidForm = computed(() => {
|
|
28
|
+
return modalState.value.name.length > 3;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const handleSubmit = () => {
|
|
32
|
+
if (isValidForm.value) {
|
|
33
|
+
emits('submit', modalState.value);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const handleCancel = () => {
|
|
38
|
+
opened.value = false;
|
|
39
|
+
};
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<PlDialogModal v-model="opened" width="600px">
|
|
44
|
+
<template #title>
|
|
45
|
+
Choose the Annotation Scheme type
|
|
46
|
+
</template>
|
|
47
|
+
<template #default>
|
|
48
|
+
<PlRadioGroup v-model="modalState.type" :options="annotationSchemaTypes" />
|
|
49
|
+
<PlTextField
|
|
50
|
+
v-model="modalState.name"
|
|
51
|
+
label="Name your Scheme"
|
|
52
|
+
min-length="3"
|
|
53
|
+
max-length="40"
|
|
54
|
+
placeholder="Annotation Name"
|
|
55
|
+
autofocus
|
|
56
|
+
required
|
|
57
|
+
/>
|
|
58
|
+
</template>
|
|
59
|
+
<template #actions>
|
|
60
|
+
<PlBtnPrimary :disabled="!isValidForm" @click.stop="handleSubmit">Apply</PlBtnPrimary>
|
|
61
|
+
<PlBtnGhost @click.stop="handleCancel">Cancel</PlBtnGhost>
|
|
62
|
+
</template>
|
|
63
|
+
</PlDialogModal>
|
|
64
|
+
</template>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { isNil } from '@milaboratories/helpers';
|
|
3
|
+
import { PlPureSlideModal, PlSidebarGroup, useConfirm } from '@milaboratories/uikit';
|
|
4
|
+
import type { AnnotationScriptUi, PObjectId } from '@platforma-sdk/model';
|
|
5
|
+
import { computed, effect, shallowRef } from 'vue';
|
|
6
|
+
import type { SimplifiedUniversalPColumnEntry } from '../types';
|
|
7
|
+
import { getDefaultAnnotationScript } from '../utils';
|
|
8
|
+
import AnnotationsSidebar from './AnnotationsSidebar.vue';
|
|
9
|
+
import FilterSidebar from './FilterSidebar.vue';
|
|
10
|
+
import PlAnnotationCreateDialog from './PlAnnotationCreateDialog.vue';
|
|
11
|
+
|
|
12
|
+
// Models
|
|
13
|
+
const annotation = defineModel<AnnotationScriptUi>('annotation', { required: true, default: getDefaultAnnotationScript });
|
|
14
|
+
const opened = defineModel<boolean>('opened', { required: true });
|
|
15
|
+
// Props
|
|
16
|
+
const props = defineProps<{
|
|
17
|
+
columns: SimplifiedUniversalPColumnEntry[];
|
|
18
|
+
hasSelectedColumns: boolean;
|
|
19
|
+
getValuesForSelectedColumns: () => Promise<undefined | { columnId: PObjectId; values: string[] }>;
|
|
20
|
+
}>();
|
|
21
|
+
// State
|
|
22
|
+
const selectedStepId = shallowRef<number | undefined>(undefined);
|
|
23
|
+
const selectedStep = computed(() => {
|
|
24
|
+
return isNil(selectedStepId.value) || isNil(annotation.value)
|
|
25
|
+
? undefined
|
|
26
|
+
: annotation.value.steps.find((step) => step.id === selectedStepId.value);
|
|
27
|
+
});
|
|
28
|
+
const hasAnnotation = computed(() => annotation.value.isCreated === true);
|
|
29
|
+
|
|
30
|
+
const openedDialog = computed({
|
|
31
|
+
get: () => !hasAnnotation.value && opened.value,
|
|
32
|
+
set: (value: boolean) => (opened.value = value),
|
|
33
|
+
});
|
|
34
|
+
const openedModal = computed({
|
|
35
|
+
get: () => hasAnnotation.value && opened.value,
|
|
36
|
+
set: (value: boolean) => (opened.value = value),
|
|
37
|
+
});
|
|
38
|
+
// Watchers
|
|
39
|
+
effect(function setDefaultStepId() {
|
|
40
|
+
if (selectedStepId.value === undefined && annotation.value.steps.length > 0) {
|
|
41
|
+
selectedStepId.value = annotation.value.steps[0].id;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
// Hooks
|
|
45
|
+
const confirmResetSchema = useConfirm({
|
|
46
|
+
title: 'Reset Schema',
|
|
47
|
+
message: 'Are you sure you want to reset the schema? This action cannot be undone.',
|
|
48
|
+
confirmLabel: 'Yes, reset',
|
|
49
|
+
cancelLabel: 'No, cancel',
|
|
50
|
+
});
|
|
51
|
+
// Actions
|
|
52
|
+
function handleCreateAnnotation(props: { type: 'byClonotype' | 'bySampleAndClonotype'; name: string }) {
|
|
53
|
+
annotation.value.isCreated = true;
|
|
54
|
+
annotation.value.mode = props.type;
|
|
55
|
+
annotation.value.title = props.name;
|
|
56
|
+
annotation.value.steps = [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function handleDeleteSchema() {
|
|
60
|
+
if (await confirmResetSchema()) {
|
|
61
|
+
annotation.value.isCreated = false;
|
|
62
|
+
annotation.value.title = '';
|
|
63
|
+
annotation.value.mode = 'byClonotype';
|
|
64
|
+
annotation.value.steps = [];
|
|
65
|
+
opened.value = false;
|
|
66
|
+
selectedStepId.value = undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<template>
|
|
73
|
+
<PlAnnotationCreateDialog v-model="openedDialog" @submit="handleCreateAnnotation"/>
|
|
74
|
+
<PlPureSlideModal v-model="openedModal" :class="$style.modal" width="768px">
|
|
75
|
+
<PlSidebarGroup :class="$style.sidebarGroup">
|
|
76
|
+
<template #item-0>
|
|
77
|
+
<AnnotationsSidebar
|
|
78
|
+
v-model:annotation="annotation"
|
|
79
|
+
v-model:selectedStepId="selectedStepId"
|
|
80
|
+
:class="$style.sidebarItem"
|
|
81
|
+
:columns="props.columns"
|
|
82
|
+
@delete-schema="handleDeleteSchema"
|
|
83
|
+
/>
|
|
84
|
+
</template>
|
|
85
|
+
<template #item-1>
|
|
86
|
+
<FilterSidebar
|
|
87
|
+
v-if="selectedStep"
|
|
88
|
+
v-model:step="selectedStep"
|
|
89
|
+
:class="$style.sidebarItem"
|
|
90
|
+
:columns="props.columns"
|
|
91
|
+
:selectedStepId="selectedStepId"
|
|
92
|
+
:hasSelectedColumns="props.hasSelectedColumns"
|
|
93
|
+
:getValuesForSelectedColumns="props.getValuesForSelectedColumns"
|
|
94
|
+
/>
|
|
95
|
+
</template>
|
|
96
|
+
</PlSidebarGroup>
|
|
97
|
+
</PlPureSlideModal>
|
|
98
|
+
</template>
|
|
99
|
+
|
|
100
|
+
<style lang="scss" module>
|
|
101
|
+
.modal {
|
|
102
|
+
display: flex;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.sidebarGroup {
|
|
106
|
+
width: 100%;
|
|
107
|
+
height: 100%;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.sidebarItem {
|
|
111
|
+
width: 100%;
|
|
112
|
+
height: 100%;
|
|
113
|
+
}
|
|
114
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as PlAnnotationsModal } from './components/PlAnnotationsModal.vue';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PColumnSpec, SUniversalPColumnId } from '@platforma-sdk/model';
|
|
2
|
+
|
|
3
|
+
export type SimplifiedPColumnSpec = Pick<PColumnSpec, 'valueType' | 'annotations'>;
|
|
4
|
+
|
|
5
|
+
export type SimplifiedUniversalPColumnEntry = {
|
|
6
|
+
id: SUniversalPColumnId;
|
|
7
|
+
label: string;
|
|
8
|
+
obj: SimplifiedPColumnSpec;
|
|
9
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AnnotationScriptUi, FilterUi, TypeFieldRecord } from '@platforma-sdk/model';
|
|
2
|
+
|
|
3
|
+
export function getDefaultAnnotationScript(): AnnotationScriptUi {
|
|
4
|
+
return {
|
|
5
|
+
isCreated: false,
|
|
6
|
+
title: 'My Annotation',
|
|
7
|
+
mode: 'byClonotype',
|
|
8
|
+
steps: [],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function createDefaultFilterMetadata<T extends Extract<FilterUi, { column: unknown }>>(): TypeFieldRecord<T> {
|
|
13
|
+
return {
|
|
14
|
+
column: {
|
|
15
|
+
label: 'Column',
|
|
16
|
+
fieldType: 'SUniversalPColumnId',
|
|
17
|
+
defaultValue: () => undefined,
|
|
18
|
+
},
|
|
19
|
+
type: {
|
|
20
|
+
label: 'Predicate',
|
|
21
|
+
fieldType: 'FilterUiType',
|
|
22
|
+
defaultValue: () => undefined,
|
|
23
|
+
},
|
|
24
|
+
} as TypeFieldRecord<T>;
|
|
25
|
+
};
|
package/src/lib.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ExpandTransition.vue2.js","sources":["../../../../../../../../../lib/ui/uikit/src/components/PlAccordion/ExpandTransition.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nconst onStart = (el: Element) => {\n el.classList.add('expand-collapse-fix');\n (el as HTMLElement).style.setProperty('--component-height', el.scrollHeight + 'px');\n};\n\nconst onAfter = (el: Element) => {\n (el as HTMLElement).style.removeProperty('--component-height');\n el.classList.remove('expand-collapse-fix');\n};\n</script>\n\n<template>\n <Transition name=\"expand-collapse\" @enter=\"onStart\" @leave=\"onStart\" @after-enter=\"onAfter\" @after-leave=\"onAfter\">\n <slot/>\n </Transition>\n</template>\n\n<style>\n.expand-collapse-fix {\n overflow: hidden;\n}\n\n.expand-collapse-enter-active,\n.expand-collapse-leave-active {\n transition:\n height 0.2s ease-in-out,\n opacity 0.2s ease-in-out;\n height: var(--component-height);\n}\n\n.expand-collapse-enter-from,\n.expand-collapse-leave-to {\n opacity: 0.5;\n height: 0;\n}\n</style>\n"],"names":["onStart","el","onAfter"],"mappings":";;;;AACMA,UAAAA,IAAU,CAACC,MAAgB;AAC5BA,QAAA,UAAU,IAAI,qBAAqB,GACrCA,EAAmB,MAAM,YAAY,sBAAsBA,EAAG,eAAe,IAAI;AAAA,IAAA,GAG9EC,IAAU,CAACD,MAAgB;AAC9BA,QAAmB,MAAM,eAAe,oBAAoB,GAC1DA,EAAA,UAAU,OAAO,qBAAqB;AAAA,IAC3C;;;;;;;;;;;;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SvgRequired.vue.js","sources":["../../../../../../../../../../../lib/ui/uikit/src/generated/components/svg/images/SvgRequired.vue"],"sourcesContent":["<!-- ⚠️ AUTOGENERATED. DO NOT EDIT. -->\n<script lang=\"ts\">\nimport '../svg-styles.css';\nexport default { name: 'SvgRequired' };\n</script>\n\n<template>\n <div class=\"svg-icon SvgRequired\" style=\"width: 5px; height: 12px\" />\n</template>\n\n<style>\n .SvgRequired { background-image: url(\"data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%225%22%20height%3D%2212%22%20viewBox%3D%220%200%205%2012%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M1.51685%204.8L2.5%203.34159L3.47612%204.8L4.39607%204.12743L3.31461%202.7469L5%202.25133L4.64888%201.16106L3.00562%201.77699L3.06882%200H1.93118L1.99438%201.77699L0.351124%201.16106L0%202.25133L1.68539%202.7469L0.59691%204.12743L1.51685%204.8Z%22%20fill%3D%22%23F1222F%22%2F%3E%3C%2Fsvg%3E\"); }\n</style>\n"],"names":[],"mappings":";;;;;;;;;;;;;AAOoC,MAAA,IAAA;AAAA,EAAA,OAAA;AAAA;;;;;;"}
|