@genspectrum/dashboard-components 0.12.0 → 0.13.0
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/custom-elements.json +117 -28
- package/dist/{LocationChangedEvent-CORvQvXv.js → LineageFilterChangedEvent-GedKNGFI.js} +25 -3
- package/dist/LineageFilterChangedEvent-GedKNGFI.js.map +1 -0
- package/dist/components.d.ts +86 -52
- package/dist/components.js +251 -196
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +59 -45
- package/dist/util.js +3 -1
- package/package.json +1 -1
- package/src/preact/components/downshift-combobox.tsx +145 -0
- package/src/preact/lineageFilter/LineageFilterChangedEvent.ts +11 -0
- package/src/preact/lineageFilter/fetchLineageAutocompleteList.spec.ts +16 -2
- package/src/preact/lineageFilter/fetchLineageAutocompleteList.ts +13 -2
- package/src/preact/lineageFilter/lineage-filter.stories.tsx +110 -9
- package/src/preact/lineageFilter/lineage-filter.tsx +40 -50
- package/src/preact/locationFilter/LocationChangedEvent.ts +1 -1
- package/src/preact/locationFilter/fetchAutocompletionList.spec.ts +6 -2
- package/src/preact/locationFilter/fetchAutocompletionList.ts +16 -6
- package/src/preact/locationFilter/location-filter.stories.tsx +33 -30
- package/src/preact/locationFilter/location-filter.tsx +47 -144
- package/src/preact/map/sequences-by-location-map.tsx +3 -3
- package/src/preact/textInput/TextInputChangedEvent.ts +11 -0
- package/src/preact/textInput/fetchStringAutocompleteList.ts +20 -0
- package/src/preact/textInput/text-input.stories.tsx +34 -14
- package/src/preact/textInput/text-input.tsx +47 -45
- package/src/types.ts +3 -0
- package/src/utilEntrypoint.ts +2 -0
- package/src/web-components/input/gs-lineage-filter.stories.ts +120 -31
- package/src/web-components/input/gs-lineage-filter.tsx +24 -8
- package/src/web-components/input/gs-location-filter.stories.ts +9 -0
- package/src/web-components/input/gs-location-filter.tsx +21 -3
- package/src/web-components/input/gs-text-input.stories.ts +44 -12
- package/src/web-components/input/gs-text-input.tsx +23 -7
- package/standalone-bundle/dashboard-components.js +4931 -4863
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/dist/LocationChangedEvent-CORvQvXv.js.map +0 -1
- package/src/preact/textInput/fetchAutocompleteList.ts +0 -9
package/custom-elements.json
CHANGED
|
@@ -534,15 +534,31 @@
|
|
|
534
534
|
"type": {
|
|
535
535
|
"text": "Meta<Required<LineageFilterProps>>"
|
|
536
536
|
},
|
|
537
|
-
"default": "{ title: 'Input/Lineage filter', component: 'gs-lineage-filter', parameters: withComponentDocs({ actions: { handles: ['gs-lineage-filter-changed', ...previewHandles], }, fetchMock: { mocks: [ { matcher: { name: 'pangoLineage', url: AGGREGATED_ENDPOINT, body: { fields: ['pangoLineage'], }, }, response: { status: 200, body: aggregatedData, }, }, ], }, componentDocs: { opensShadowDom: true, expectsChildren: false, codeExample, }, }), tags: ['autodocs'], }"
|
|
537
|
+
"default": "{ title: 'Input/Lineage filter', component: 'gs-lineage-filter', parameters: withComponentDocs({ actions: { handles: ['gs-lineage-filter-changed', ...previewHandles], }, fetchMock: { mocks: [ { matcher: { name: 'pangoLineage', url: AGGREGATED_ENDPOINT, body: { fields: ['pangoLineage'], country: 'Germany', }, }, response: { status: 200, body: aggregatedData, }, }, ], }, componentDocs: { opensShadowDom: true, expectsChildren: false, codeExample, }, }), tags: ['autodocs'], argTypes: { lapisField: { control: { type: 'select', }, options: ['host'], }, placeholderText: { control: { type: 'text', }, }, value: { control: { type: 'text', }, }, width: { control: { type: 'text', }, }, lapisFilter: { control: { type: 'object', }, }, }, }"
|
|
538
538
|
},
|
|
539
539
|
{
|
|
540
540
|
"kind": "variable",
|
|
541
|
-
"name": "
|
|
541
|
+
"name": "LineageFilter",
|
|
542
|
+
"type": {
|
|
543
|
+
"text": "StoryObj<Required<LineageFilterProps>>"
|
|
544
|
+
},
|
|
545
|
+
"default": "{ ...Template, play: async ({ canvasElement }) => { const canvas = await withinShadowRoot(canvasElement, 'gs-lineage-filter'); await waitFor(() => { return expect(canvas.getByPlaceholderText('Enter a lineage')).toBeVisible(); }); }, }"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"kind": "variable",
|
|
549
|
+
"name": "DelayToShowLoadingState",
|
|
542
550
|
"type": {
|
|
543
551
|
"text": "StoryObj<Required<LineageFilterProps>>"
|
|
544
552
|
},
|
|
545
|
-
"default": "{
|
|
553
|
+
"default": "{ ...Template, parameters: { fetchMock: { mocks: [ { matcher: aggregatedEndpointMatcher, response: { status: 200, body: aggregatedData, }, options: { delay: 5000, }, }, ], }, }, }"
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
"kind": "variable",
|
|
557
|
+
"name": "FetchingLocationsFails",
|
|
558
|
+
"type": {
|
|
559
|
+
"text": "StoryObj<Required<LineageFilterProps>>"
|
|
560
|
+
},
|
|
561
|
+
"default": "{ ...Template, parameters: { fetchMock: { mocks: [ { matcher: aggregatedEndpointMatcher, response: { status: 400, body: { error: { status: 400, detail: 'Dummy error message from mock LAPIS', type: 'about:blank' }, }, }, }, ], }, }, play: async ({ canvasElement }) => { const canvas = await withinShadowRoot(canvasElement, 'gs-lineage-filter'); await waitFor(() => expect(canvas.getByText('Oops! Something went wrong.', { exact: false })).toBeInTheDocument(), ); }, }"
|
|
546
562
|
},
|
|
547
563
|
{
|
|
548
564
|
"kind": "variable",
|
|
@@ -550,7 +566,7 @@
|
|
|
550
566
|
"type": {
|
|
551
567
|
"text": "StoryObj<Required<LineageFilterProps>>"
|
|
552
568
|
},
|
|
553
|
-
"default": "{ ...
|
|
569
|
+
"default": "{ ...LineageFilter, play: async ({ canvasElement, step }) => { const canvas = await withinShadowRoot(canvasElement, 'gs-lineage-filter'); const inputField = () => canvas.getByPlaceholderText('Enter a lineage'); const listenerMock = fn(); await step('Setup event listener mock', async () => { canvasElement.addEventListener('gs-lineage-filter-changed', listenerMock); }); await step('wait until data is loaded', async () => { await waitFor(() => { return expect(inputField()).toBeEnabled(); }); }); await step('Enters an invalid lineage value', async () => { await userEvent.type(inputField(), 'notInList'); await expect(listenerMock).not.toHaveBeenCalled(); }); await step('Empty input', async () => { await userEvent.type(inputField(), '{backspace>9/}'); await userEvent.click(canvas.getByLabelText('toggle menu')); await waitFor(() => { return expect(listenerMock.mock.calls.at(-1)![0].detail).toStrictEqual({ pangoLineage: undefined, }); }); }); await step('Enter a valid lineage value', async () => { await userEvent.type(inputField(), 'B.1.1.7*'); await userEvent.click(canvas.getByRole('option', { name: 'B.1.1.7*' })); await waitFor(() => { return expect(listenerMock.mock.calls.at(-1)![0].detail).toStrictEqual({ pangoLineage: 'B.1.1.7*', }); }); }); }, args: { ...LineageFilter.args, value: '', }, }"
|
|
554
570
|
}
|
|
555
571
|
],
|
|
556
572
|
"exports": [
|
|
@@ -564,9 +580,25 @@
|
|
|
564
580
|
},
|
|
565
581
|
{
|
|
566
582
|
"kind": "js",
|
|
567
|
-
"name": "
|
|
583
|
+
"name": "LineageFilter",
|
|
568
584
|
"declaration": {
|
|
569
|
-
"name": "
|
|
585
|
+
"name": "LineageFilter",
|
|
586
|
+
"module": "src/web-components/input/gs-lineage-filter.stories.ts"
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
"kind": "js",
|
|
591
|
+
"name": "DelayToShowLoadingState",
|
|
592
|
+
"declaration": {
|
|
593
|
+
"name": "DelayToShowLoadingState",
|
|
594
|
+
"module": "src/web-components/input/gs-lineage-filter.stories.ts"
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
"kind": "js",
|
|
599
|
+
"name": "FetchingLocationsFails",
|
|
600
|
+
"declaration": {
|
|
601
|
+
"name": "FetchingLocationsFails",
|
|
570
602
|
"module": "src/web-components/input/gs-lineage-filter.stories.ts"
|
|
571
603
|
}
|
|
572
604
|
},
|
|
@@ -586,18 +618,18 @@
|
|
|
586
618
|
"declarations": [
|
|
587
619
|
{
|
|
588
620
|
"kind": "class",
|
|
589
|
-
"description": "\n## Context\n\nThis component provides a text input field to filter by lineages.\nCurrently, it is designed to work well with Pango Lineages,\nbut it may also be used for other lineage types, if suitable.\n\nIt fetches all available values of the `lapisField` from the LAPIS instance
|
|
621
|
+
"description": "\n## Context\n\nThis component provides a text input field to filter by lineages.\nCurrently, it is designed to work well with Pango Lineages,\nbut it may also be used for other lineage types, if suitable.\n\nIt fetches all available values of the `lapisField` from the LAPIS instance within the given `lapisFilter`\nand provides an autocomplete list with the available values of the lineage and sublineage queries\n(a `*` appended to the lineage value).",
|
|
590
622
|
"name": "LineageFilterComponent",
|
|
591
623
|
"members": [
|
|
592
624
|
{
|
|
593
625
|
"kind": "field",
|
|
594
|
-
"name": "
|
|
626
|
+
"name": "value",
|
|
595
627
|
"type": {
|
|
596
628
|
"text": "string"
|
|
597
629
|
},
|
|
598
630
|
"default": "''",
|
|
599
631
|
"description": "The initial value to use for this lineage filter.",
|
|
600
|
-
"attribute": "
|
|
632
|
+
"attribute": "value"
|
|
601
633
|
},
|
|
602
634
|
{
|
|
603
635
|
"kind": "field",
|
|
@@ -609,6 +641,16 @@
|
|
|
609
641
|
"description": "Required.\n\nThe LAPIS field name to use for this lineage filter.\nThe field must exist on this LAPIS instance.",
|
|
610
642
|
"attribute": "lapisField"
|
|
611
643
|
},
|
|
644
|
+
{
|
|
645
|
+
"kind": "field",
|
|
646
|
+
"name": "lapisFilter",
|
|
647
|
+
"type": {
|
|
648
|
+
"text": "Record<string, string | string[] | number | null | boolean | undefined> & {\n nucleotideMutations?: string[];\n aminoAcidMutations?: string[];\n nucleotideInsertions?: string[];\n aminoAcidInsertions?: string[];\n }"
|
|
649
|
+
},
|
|
650
|
+
"default": "{}",
|
|
651
|
+
"description": "The filter that is used to fetch the available the autocomplete options.\nIf not set it fetches all available options.\nIt must be a valid LAPIS filter object.",
|
|
652
|
+
"attribute": "lapisFilter"
|
|
653
|
+
},
|
|
612
654
|
{
|
|
613
655
|
"kind": "field",
|
|
614
656
|
"name": "placeholderText",
|
|
@@ -633,7 +675,7 @@
|
|
|
633
675
|
"events": [
|
|
634
676
|
{
|
|
635
677
|
"type": {
|
|
636
|
-
"text": "CustomEvent<Record<string, string>>"
|
|
678
|
+
"text": "CustomEvent<Record<string, string | undefined>>"
|
|
637
679
|
},
|
|
638
680
|
"description": "Fired when the input field is changed. The `details` of this event contain an object with the `lapisField` as key and the input value as value. Example: ``` { \"pangoLineage\": \"B.1.1.7\" } ```",
|
|
639
681
|
"name": "gs-lineage-filter-changed"
|
|
@@ -641,13 +683,13 @@
|
|
|
641
683
|
],
|
|
642
684
|
"attributes": [
|
|
643
685
|
{
|
|
644
|
-
"name": "
|
|
686
|
+
"name": "value",
|
|
645
687
|
"type": {
|
|
646
688
|
"text": "string"
|
|
647
689
|
},
|
|
648
690
|
"default": "''",
|
|
649
691
|
"description": "The initial value to use for this lineage filter.",
|
|
650
|
-
"fieldName": "
|
|
692
|
+
"fieldName": "value"
|
|
651
693
|
},
|
|
652
694
|
{
|
|
653
695
|
"name": "lapisField",
|
|
@@ -658,6 +700,15 @@
|
|
|
658
700
|
"description": "Required.\n\nThe LAPIS field name to use for this lineage filter.\nThe field must exist on this LAPIS instance.",
|
|
659
701
|
"fieldName": "lapisField"
|
|
660
702
|
},
|
|
703
|
+
{
|
|
704
|
+
"name": "lapisFilter",
|
|
705
|
+
"type": {
|
|
706
|
+
"text": "Record<string, string | string[] | number | null | boolean | undefined> & {\n nucleotideMutations?: string[];\n aminoAcidMutations?: string[];\n nucleotideInsertions?: string[];\n aminoAcidInsertions?: string[];\n }"
|
|
707
|
+
},
|
|
708
|
+
"default": "{}",
|
|
709
|
+
"description": "The filter that is used to fetch the available the autocomplete options.\nIf not set it fetches all available options.\nIt must be a valid LAPIS filter object.",
|
|
710
|
+
"fieldName": "lapisFilter"
|
|
711
|
+
},
|
|
661
712
|
{
|
|
662
713
|
"name": "placeholderText",
|
|
663
714
|
"type": {
|
|
@@ -714,7 +765,7 @@
|
|
|
714
765
|
"type": {
|
|
715
766
|
"text": "Meta"
|
|
716
767
|
},
|
|
717
|
-
"default": "{ title: 'Input/Location filter', component: 'gs-location-filter', parameters: withComponentDocs({ actions: { handles: ['gs-location-changed', ...previewHandles], }, componentDocs: { opensShadowDom: true, expectsChildren: false, codeExample, }, }), argTypes: { fields: { control: { type: 'object', }, }, value: { control: { type: 'object', }, }, width: { control: { type: 'text', }, }, placeholderText: { control: { type: 'text', }, }, }, tags: ['autodocs'], }"
|
|
768
|
+
"default": "{ title: 'Input/Location filter', component: 'gs-location-filter', parameters: withComponentDocs({ actions: { handles: ['gs-location-changed', ...previewHandles], }, componentDocs: { opensShadowDom: true, expectsChildren: false, codeExample, }, }), argTypes: { fields: { control: { type: 'object', }, }, value: { control: { type: 'object', }, }, width: { control: { type: 'text', }, }, placeholderText: { control: { type: 'text', }, }, lapisFilter: { age: 18, }, }, tags: ['autodocs'], }"
|
|
718
769
|
},
|
|
719
770
|
{
|
|
720
771
|
"kind": "variable",
|
|
@@ -798,14 +849,14 @@
|
|
|
798
849
|
"declarations": [
|
|
799
850
|
{
|
|
800
851
|
"kind": "class",
|
|
801
|
-
"description": "## Context\n\nThis component provides an input field to specify filters for locations.\n\nIt expects a list of fields that form a strict hierarchical order, such as continent, country, and city.\nThe component retrieves a list of all possible values for these fields from the Lapis instance
|
|
852
|
+
"description": "## Context\n\nThis component provides an input field to specify filters for locations.\n\nIt expects a list of fields that form a strict hierarchical order, such as continent, country, and city.\nThe component retrieves a list of all possible values for these fields from the Lapis instance,\nwithin the `lapisFilter`.\nThis list is then utilized to display autocomplete suggestions and to validate the input.",
|
|
802
853
|
"name": "LocationFilterComponent",
|
|
803
854
|
"members": [
|
|
804
855
|
{
|
|
805
856
|
"kind": "field",
|
|
806
857
|
"name": "value",
|
|
807
858
|
"type": {
|
|
808
|
-
"text": "Record<string, string |
|
|
859
|
+
"text": "Record<string, string | undefined> | undefined"
|
|
809
860
|
},
|
|
810
861
|
"default": "undefined",
|
|
811
862
|
"description": "The initial value to use for this location filter.",
|
|
@@ -821,6 +872,16 @@
|
|
|
821
872
|
"description": "Required.\n\nThe fields to display in the location filter, in hierarchical order.\nThe top-level field should be the first entry in the array.\nThis component assumes that the values for each field form a strict hierarchy\n(e.g., `fields = ['continent', 'country', 'city']`).",
|
|
822
873
|
"attribute": "fields"
|
|
823
874
|
},
|
|
875
|
+
{
|
|
876
|
+
"kind": "field",
|
|
877
|
+
"name": "lapisFilter",
|
|
878
|
+
"type": {
|
|
879
|
+
"text": "Record<string, string | string[] | number | null | boolean | undefined> & {\n nucleotideMutations?: string[];\n aminoAcidMutations?: string[];\n nucleotideInsertions?: string[];\n aminoAcidInsertions?: string[];\n }"
|
|
880
|
+
},
|
|
881
|
+
"default": "{}",
|
|
882
|
+
"description": "The filter that is used to fetch the available the autocomplete options.\nIf not set it fetches all available options.\nIt must be a valid LAPIS filter object.",
|
|
883
|
+
"attribute": "lapisFilter"
|
|
884
|
+
},
|
|
824
885
|
{
|
|
825
886
|
"kind": "field",
|
|
826
887
|
"name": "width",
|
|
@@ -845,7 +906,7 @@
|
|
|
845
906
|
"events": [
|
|
846
907
|
{
|
|
847
908
|
"type": {
|
|
848
|
-
"text": "CustomEvent<Record<string, string>>"
|
|
909
|
+
"text": "CustomEvent<Record<string, string | undefined>>"
|
|
849
910
|
},
|
|
850
911
|
"description": "Fired when a value from the datalist is selected or when a valid value is typed into the field. The `details` of this event contain an object with all `fields` as keys and the corresponding values as values, even if they are `undefined`. Example: ``` { continent: \"Asia\", country: \"China\", city: \"Beijing\", district: undefined, } ```",
|
|
851
912
|
"name": "gs-location-changed"
|
|
@@ -855,7 +916,7 @@
|
|
|
855
916
|
{
|
|
856
917
|
"name": "value",
|
|
857
918
|
"type": {
|
|
858
|
-
"text": "Record<string, string |
|
|
919
|
+
"text": "Record<string, string | undefined> | undefined"
|
|
859
920
|
},
|
|
860
921
|
"default": "undefined",
|
|
861
922
|
"description": "The initial value to use for this location filter.",
|
|
@@ -870,6 +931,15 @@
|
|
|
870
931
|
"description": "Required.\n\nThe fields to display in the location filter, in hierarchical order.\nThe top-level field should be the first entry in the array.\nThis component assumes that the values for each field form a strict hierarchy\n(e.g., `fields = ['continent', 'country', 'city']`).",
|
|
871
932
|
"fieldName": "fields"
|
|
872
933
|
},
|
|
934
|
+
{
|
|
935
|
+
"name": "lapisFilter",
|
|
936
|
+
"type": {
|
|
937
|
+
"text": "Record<string, string | string[] | number | null | boolean | undefined> & {\n nucleotideMutations?: string[];\n aminoAcidMutations?: string[];\n nucleotideInsertions?: string[];\n aminoAcidInsertions?: string[];\n }"
|
|
938
|
+
},
|
|
939
|
+
"default": "{}",
|
|
940
|
+
"description": "The filter that is used to fetch the available the autocomplete options.\nIf not set it fetches all available options.\nIt must be a valid LAPIS filter object.",
|
|
941
|
+
"fieldName": "lapisFilter"
|
|
942
|
+
},
|
|
873
943
|
{
|
|
874
944
|
"name": "width",
|
|
875
945
|
"type": {
|
|
@@ -1084,7 +1154,7 @@
|
|
|
1084
1154
|
"type": {
|
|
1085
1155
|
"text": "Meta<Required<TextInputProps>>"
|
|
1086
1156
|
},
|
|
1087
|
-
"default": "{ title: 'Input/Text input', component: 'gs-text-input', parameters: withComponentDocs({ actions: { handles: ['gs-text-input-changed', ...previewHandles], }, fetchMock: { mocks: [ { matcher: { name: 'hosts', url: AGGREGATED_ENDPOINT, body: { fields: ['host'], }, }, response: { status: 200, body: data, }, }, ], }, componentDocs: { opensShadowDom: true, expectsChildren: false, codeExample, }, }), argTypes: { lapisField: { control: { type: 'text', }, }, placeholderText: { control: { type: 'text', }, },
|
|
1157
|
+
"default": "{ title: 'Input/Text input', component: 'gs-text-input', parameters: withComponentDocs({ actions: { handles: ['gs-text-input-changed', ...previewHandles], }, fetchMock: { mocks: [ { matcher: { name: 'hosts', url: AGGREGATED_ENDPOINT, body: { fields: ['host'], country: 'Germany', }, }, response: { status: 200, body: data, }, }, ], }, componentDocs: { opensShadowDom: true, expectsChildren: false, codeExample, }, }), argTypes: { lapisField: { control: { type: 'text', }, }, placeholderText: { control: { type: 'text', }, }, value: { control: { type: 'text', }, }, width: { control: { type: 'text', }, }, lapisFilter: { control: { type: 'object', }, }, }, tags: ['autodocs'], }"
|
|
1088
1158
|
},
|
|
1089
1159
|
{
|
|
1090
1160
|
"kind": "variable",
|
|
@@ -1092,15 +1162,15 @@
|
|
|
1092
1162
|
"type": {
|
|
1093
1163
|
"text": "StoryObj<Required<TextInputProps>>"
|
|
1094
1164
|
},
|
|
1095
|
-
"default": "{ render: (args) => { return html` <gs-app lapis=\"${LAPIS_URL}\"> <div class=\"max-w-screen-lg\"> <gs-text-input .lapisField=${args.lapisField} .placeholderText=${args.placeholderText} .
|
|
1165
|
+
"default": "{ render: (args) => { return html` <gs-app lapis=\"${LAPIS_URL}\"> <div class=\"max-w-screen-lg\"> <gs-text-input .lapisField=${args.lapisField} .lapisFilter=${args.lapisFilter} .placeholderText=${args.placeholderText} .value=${args.value} .width=${args.width} ></gs-text-input> </div> </gs-app>`; }, args: { lapisField: 'host', lapisFilter: { country: 'Germany' }, placeholderText: 'Enter host name', value: 'Homo sapiens', width: '100%', }, }"
|
|
1096
1166
|
},
|
|
1097
1167
|
{
|
|
1098
1168
|
"kind": "variable",
|
|
1099
|
-
"name": "
|
|
1169
|
+
"name": "FiresEvents",
|
|
1100
1170
|
"type": {
|
|
1101
1171
|
"text": "StoryObj<Required<TextInputProps>>"
|
|
1102
1172
|
},
|
|
1103
|
-
"default": "{ ...Default, play: async ({ canvasElement, step }) => { const canvas = await withinShadowRoot(canvasElement, 'gs-text-input'); const inputField = () => canvas.getByPlaceholderText('Enter host name'); const listenerMock = fn(); await step('Setup event listener mock', async () => { canvasElement.addEventListener('gs-text-input-changed', listenerMock); }); await step('wait until data is loaded', async () => { await waitFor(() => { return expect(inputField()).toBeEnabled(); }); }); await step('Enters an invalid host name', async () => { await userEvent.type(inputField(), 'notInList'); await expect(listenerMock).not.toHaveBeenCalled(); }); await step('Empty input', async () => { await userEvent.type(inputField(), '{backspace>9/}'); await
|
|
1173
|
+
"default": "{ ...Default, play: async ({ canvasElement, step }) => { const canvas = await withinShadowRoot(canvasElement, 'gs-text-input'); const inputField = () => canvas.getByPlaceholderText('Enter host name'); const listenerMock = fn(); await step('Setup event listener mock', async () => { canvasElement.addEventListener('gs-text-input-changed', listenerMock); }); await step('wait until data is loaded', async () => { await waitFor(() => { return expect(inputField()).toBeEnabled(); }); }); await step('Enters an invalid host name', async () => { await userEvent.type(inputField(), 'notInList'); await expect(listenerMock).not.toHaveBeenCalled(); }); await step('Empty input', async () => { await userEvent.type(inputField(), '{backspace>9/}'); }); await step('Enter a valid host name', async () => { await userEvent.type(inputField(), 'Homo s'); const dropdownOption = await canvas.findByText('Homo sapiens'); await userEvent.click(dropdownOption); }); await step('Verify event is fired with correct detail', async () => { await waitFor(() => { expect(listenerMock).toHaveBeenCalledWith( expect.objectContaining({ detail: { host: 'Homo sapiens', }, }), ); }); }); await step('Remove initial value', async () => { await fireEvent.click(canvas.getByRole('button', { name: 'clear selection' })); await expect(listenerMock).toHaveBeenCalledWith( expect.objectContaining({ detail: { host: undefined, }, }), ); }); await step('Empty input', async () => { inputField().blur(); await expect(listenerMock.mock.calls.at(-1)![0].detail).toStrictEqual({ host: undefined, }); }); }, args: { ...Default.args, value: '', }, }"
|
|
1104
1174
|
}
|
|
1105
1175
|
],
|
|
1106
1176
|
"exports": [
|
|
@@ -1122,9 +1192,9 @@
|
|
|
1122
1192
|
},
|
|
1123
1193
|
{
|
|
1124
1194
|
"kind": "js",
|
|
1125
|
-
"name": "
|
|
1195
|
+
"name": "FiresEvents",
|
|
1126
1196
|
"declaration": {
|
|
1127
|
-
"name": "
|
|
1197
|
+
"name": "FiresEvents",
|
|
1128
1198
|
"module": "src/web-components/input/gs-text-input.stories.ts"
|
|
1129
1199
|
}
|
|
1130
1200
|
}
|
|
@@ -1141,13 +1211,13 @@
|
|
|
1141
1211
|
"members": [
|
|
1142
1212
|
{
|
|
1143
1213
|
"kind": "field",
|
|
1144
|
-
"name": "
|
|
1214
|
+
"name": "value",
|
|
1145
1215
|
"type": {
|
|
1146
1216
|
"text": "string | undefined"
|
|
1147
1217
|
},
|
|
1148
1218
|
"default": "undefined",
|
|
1149
1219
|
"description": "The initial value to use for this text input.",
|
|
1150
|
-
"attribute": "
|
|
1220
|
+
"attribute": "value"
|
|
1151
1221
|
},
|
|
1152
1222
|
{
|
|
1153
1223
|
"kind": "field",
|
|
@@ -1159,6 +1229,16 @@
|
|
|
1159
1229
|
"description": "Required.\n\nThe LAPIS field name to use for this text input.\nThe field must exist on this LAPIS instance.",
|
|
1160
1230
|
"attribute": "lapisField"
|
|
1161
1231
|
},
|
|
1232
|
+
{
|
|
1233
|
+
"kind": "field",
|
|
1234
|
+
"name": "lapisFilter",
|
|
1235
|
+
"type": {
|
|
1236
|
+
"text": "Record<string, string | string[] | number | null | boolean | undefined> & {\n nucleotideMutations?: string[];\n aminoAcidMutations?: string[];\n nucleotideInsertions?: string[];\n aminoAcidInsertions?: string[];\n }"
|
|
1237
|
+
},
|
|
1238
|
+
"default": "{}",
|
|
1239
|
+
"description": "The filter that is used to fetch the available the autocomplete options.\nIf not set it fetches all available options.\nIt must be a valid LAPIS filter object.",
|
|
1240
|
+
"attribute": "lapisFilter"
|
|
1241
|
+
},
|
|
1162
1242
|
{
|
|
1163
1243
|
"kind": "field",
|
|
1164
1244
|
"name": "placeholderText",
|
|
@@ -1183,7 +1263,7 @@
|
|
|
1183
1263
|
"events": [
|
|
1184
1264
|
{
|
|
1185
1265
|
"type": {
|
|
1186
|
-
"text": "CustomEvent<Record<string, string>>"
|
|
1266
|
+
"text": "CustomEvent<Record<string, string | undefined>>"
|
|
1187
1267
|
},
|
|
1188
1268
|
"description": "Fired when the input field is changed. The `details` of this event contain an object with the `lapisField` as key and the input value as value. Example: ``` { \"host\": \"Homo sapiens\" } ```",
|
|
1189
1269
|
"name": "gs-text-input-changed"
|
|
@@ -1191,13 +1271,13 @@
|
|
|
1191
1271
|
],
|
|
1192
1272
|
"attributes": [
|
|
1193
1273
|
{
|
|
1194
|
-
"name": "
|
|
1274
|
+
"name": "value",
|
|
1195
1275
|
"type": {
|
|
1196
1276
|
"text": "string | undefined"
|
|
1197
1277
|
},
|
|
1198
1278
|
"default": "undefined",
|
|
1199
1279
|
"description": "The initial value to use for this text input.",
|
|
1200
|
-
"fieldName": "
|
|
1280
|
+
"fieldName": "value"
|
|
1201
1281
|
},
|
|
1202
1282
|
{
|
|
1203
1283
|
"name": "lapisField",
|
|
@@ -1208,6 +1288,15 @@
|
|
|
1208
1288
|
"description": "Required.\n\nThe LAPIS field name to use for this text input.\nThe field must exist on this LAPIS instance.",
|
|
1209
1289
|
"fieldName": "lapisField"
|
|
1210
1290
|
},
|
|
1291
|
+
{
|
|
1292
|
+
"name": "lapisFilter",
|
|
1293
|
+
"type": {
|
|
1294
|
+
"text": "Record<string, string | string[] | number | null | boolean | undefined> & {\n nucleotideMutations?: string[];\n aminoAcidMutations?: string[];\n nucleotideInsertions?: string[];\n aminoAcidInsertions?: string[];\n }"
|
|
1295
|
+
},
|
|
1296
|
+
"default": "{}",
|
|
1297
|
+
"description": "The filter that is used to fetch the available the autocomplete options.\nIf not set it fetches all available options.\nIt must be a valid LAPIS filter object.",
|
|
1298
|
+
"fieldName": "lapisFilter"
|
|
1299
|
+
},
|
|
1211
1300
|
{
|
|
1212
1301
|
"name": "placeholderText",
|
|
1213
1302
|
"type": {
|
|
@@ -10,6 +10,7 @@ const namedLapisFilterSchema = z.object({
|
|
|
10
10
|
lapisFilter: lapisFilterSchema,
|
|
11
11
|
displayName: z.string()
|
|
12
12
|
});
|
|
13
|
+
const lapisLocationFilterSchema = z.record(z.union([z.string(), z.undefined()]));
|
|
13
14
|
const temporalGranularitySchema = z.union([
|
|
14
15
|
z.literal("day"),
|
|
15
16
|
z.literal("week"),
|
|
@@ -105,12 +106,33 @@ class LocationChangedEvent extends CustomEvent {
|
|
|
105
106
|
});
|
|
106
107
|
}
|
|
107
108
|
}
|
|
109
|
+
class TextInputChangedEvent extends CustomEvent {
|
|
110
|
+
constructor(detail) {
|
|
111
|
+
super("gs-text-input-changed", {
|
|
112
|
+
detail,
|
|
113
|
+
bubbles: true,
|
|
114
|
+
composed: true
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
class LineageFilterChangedEvent extends CustomEvent {
|
|
119
|
+
constructor(detail) {
|
|
120
|
+
super("gs-lineage-filter-changed", {
|
|
121
|
+
detail,
|
|
122
|
+
bubbles: true,
|
|
123
|
+
composed: true
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
108
127
|
export {
|
|
109
128
|
DateRangeOptionChangedEvent as D,
|
|
110
129
|
LocationChangedEvent as L,
|
|
111
|
-
|
|
112
|
-
|
|
130
|
+
TextInputChangedEvent as T,
|
|
131
|
+
LineageFilterChangedEvent as a,
|
|
132
|
+
dateRangeOptionSchema as b,
|
|
133
|
+
toYYYYMMDD as c,
|
|
113
134
|
dateRangeOptionPresets as d,
|
|
135
|
+
lapisLocationFilterSchema as e,
|
|
114
136
|
lapisFilterSchema as l,
|
|
115
137
|
mutationsFilterSchema as m,
|
|
116
138
|
namedLapisFilterSchema as n,
|
|
@@ -118,4 +140,4 @@ export {
|
|
|
118
140
|
temporalGranularitySchema as t,
|
|
119
141
|
views as v
|
|
120
142
|
};
|
|
121
|
-
//# sourceMappingURL=
|
|
143
|
+
//# sourceMappingURL=LineageFilterChangedEvent-GedKNGFI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LineageFilterChangedEvent-GedKNGFI.js","sources":["../src/types.ts","../src/preact/dateRangeSelector/dateConversion.ts","../src/preact/dateRangeSelector/dateRangeOption.ts","../src/preact/locationFilter/LocationChangedEvent.ts","../src/preact/textInput/TextInputChangedEvent.ts","../src/preact/lineageFilter/LineageFilterChangedEvent.ts"],"sourcesContent":["import z from 'zod';\n\nimport {\n type Deletion,\n type DeletionClass,\n type Insertion,\n type InsertionClass,\n type Substitution,\n type SubstitutionClass,\n} from './utils/mutations';\n\nexport const mutationsFilterSchema = z.object({\n nucleotideMutations: z.array(z.string()),\n aminoAcidMutations: z.array(z.string()),\n nucleotideInsertions: z.array(z.string()),\n aminoAcidInsertions: z.array(z.string()),\n});\nexport type MutationsFilter = z.infer<typeof mutationsFilterSchema>;\n\nexport const lapisFilterSchema = z\n .record(z.union([z.string(), z.array(z.string()), z.number(), z.null(), z.boolean(), z.undefined()]))\n .and(mutationsFilterSchema.partial());\nexport type LapisFilter = z.infer<typeof lapisFilterSchema>;\n\nexport const namedLapisFilterSchema = z.object({\n lapisFilter: lapisFilterSchema,\n displayName: z.string(),\n});\nexport type NamedLapisFilter = z.infer<typeof namedLapisFilterSchema>;\n\nexport const lapisLocationFilterSchema = z.record(z.union([z.string(), z.undefined()]));\nexport type LapisLocationFilter = z.infer<typeof lapisLocationFilterSchema>;\n\nexport const temporalGranularitySchema = z.union([\n z.literal('day'),\n z.literal('week'),\n z.literal('month'),\n z.literal('year'),\n]);\nexport type TemporalGranularity = z.infer<typeof temporalGranularitySchema>;\n\nexport const sequenceTypeSchema = z.union([z.literal('nucleotide'), z.literal('amino acid')]);\nexport type SequenceType = z.infer<typeof sequenceTypeSchema>;\n\nexport type SubstitutionOrDeletion = 'substitution' | 'deletion';\n\nexport type MutationType = SubstitutionOrDeletion | 'insertion';\n\nexport type SubstitutionEntry<T extends Substitution = SubstitutionClass> = {\n type: 'substitution';\n mutation: T;\n count: number;\n proportion: number;\n};\n\nexport type DeletionEntry<T extends Deletion = DeletionClass> = {\n type: 'deletion';\n mutation: T;\n count: number;\n proportion: number;\n};\n\nexport type InsertionEntry<T extends Insertion = InsertionClass> = { type: 'insertion'; mutation: T; count: number };\n\nexport type SubstitutionOrDeletionEntry<\n S extends Substitution = SubstitutionClass,\n D extends Deletion = DeletionClass,\n> = SubstitutionEntry<S> | DeletionEntry<D>;\n\nexport type MutationEntry = SubstitutionEntry | DeletionEntry | InsertionEntry;\n\nexport const views = {\n table: 'table',\n venn: 'venn',\n grid: 'grid',\n insertions: 'insertions',\n bar: 'bar',\n line: 'line',\n bubble: 'bubble',\n map: 'map',\n} as const;\n","export const toYYYYMMDD = (date: Date) => {\n const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: '2-digit', day: '2-digit' };\n return date.toLocaleDateString('en-CA', options);\n};\n","import z from 'zod';\n\nimport { toYYYYMMDD } from './dateConversion';\n\n/**\n * A date range option that can be used in the `gs-date-range-selector` component.\n */\nexport const dateRangeOptionSchema = z.object({\n /** The label of the date range option that will be shown to the user */\n label: z.string(),\n /**\n * The start date of the date range in the format `YYYY-MM-DD`.\n * If not set, the date range selector will default to the `earliestDate` property.\n */\n dateFrom: z.string().date().optional(),\n /**\n * The end date of the date range in the format `YYYY-MM-DD`.\n * If not set, the date range selector will default to the current date.\n */\n dateTo: z.string().date().optional(),\n});\n\nexport type DateRangeOption = z.infer<typeof dateRangeOptionSchema>;\n\nexport type DateRangeSelectOption = string | { dateFrom: string; dateTo: string };\n\nexport class DateRangeOptionChangedEvent extends CustomEvent<DateRangeSelectOption> {\n constructor(detail: DateRangeSelectOption) {\n super('gs-date-range-option-changed', {\n detail,\n bubbles: true,\n composed: true,\n });\n }\n}\n\nconst today = new Date();\n\nconst twoWeeksAgo = new Date();\ntwoWeeksAgo.setDate(today.getDate() - 14);\n\nconst lastMonth = new Date(today);\nlastMonth.setMonth(today.getMonth() - 1);\n\nconst last2Months = new Date(today);\nlast2Months.setMonth(today.getMonth() - 2);\n\nconst last3Months = new Date(today);\nlast3Months.setMonth(today.getMonth() - 3);\n\nconst last6Months = new Date(today);\nlast6Months.setMonth(today.getMonth() - 6);\n\nconst lastYear = new Date(today);\nlastYear.setFullYear(today.getFullYear() - 1);\n\n/**\n * Presets for the `gs-date-range-selector` component that can be used as `dateRangeOptions`.\n */\nexport const dateRangeOptionPresets = {\n last2Weeks: {\n label: 'Last 2 weeks',\n dateFrom: toYYYYMMDD(twoWeeksAgo),\n },\n lastMonth: {\n label: 'Last month',\n dateFrom: toYYYYMMDD(lastMonth),\n },\n last2Months: {\n label: 'Last 2 months',\n dateFrom: toYYYYMMDD(last2Months),\n },\n last3Months: {\n label: 'Last 3 months',\n dateFrom: toYYYYMMDD(last3Months),\n },\n last6Months: {\n label: 'Last 6 months',\n dateFrom: toYYYYMMDD(last6Months),\n },\n lastYear: {\n label: 'Last year',\n dateFrom: toYYYYMMDD(lastYear),\n },\n allTimes: {\n label: 'All times',\n },\n} satisfies Record<string, DateRangeOption>;\n","import { type LapisLocationFilter } from '../../types';\n\nexport class LocationChangedEvent extends CustomEvent<LapisLocationFilter> {\n constructor(detail: LapisLocationFilter) {\n super('gs-location-changed', {\n detail,\n bubbles: true,\n composed: true,\n });\n }\n}\n","type LapisTextFilter = Record<string, string | undefined>;\n\nexport class TextInputChangedEvent extends CustomEvent<LapisTextFilter> {\n constructor(detail: LapisTextFilter) {\n super('gs-text-input-changed', {\n detail,\n bubbles: true,\n composed: true,\n });\n }\n}\n","type LapisLineageFilter = Record<string, string | undefined>;\n\nexport class LineageFilterChangedEvent extends CustomEvent<LapisLineageFilter> {\n constructor(detail: LapisLineageFilter) {\n super('gs-lineage-filter-changed', {\n detail,\n bubbles: true,\n composed: true,\n });\n }\n}\n"],"names":[],"mappings":"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"}
|