@finos/legend-query-builder 4.14.40 → 4.14.43

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.
Files changed (51) hide show
  1. package/lib/components/explorer/QueryBuilderMilestoningEditor.d.ts +0 -5
  2. package/lib/components/explorer/QueryBuilderMilestoningEditor.d.ts.map +1 -1
  3. package/lib/components/explorer/QueryBuilderMilestoningEditor.js +5 -10
  4. package/lib/components/explorer/QueryBuilderMilestoningEditor.js.map +1 -1
  5. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.d.ts.map +1 -1
  6. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js +3 -35
  7. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js.map +1 -1
  8. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  9. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +1 -11
  10. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  11. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  12. package/lib/components/filter/QueryBuilderFilterPanel.js +6 -2
  13. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  14. package/lib/components/shared/BasicValueSpecificationEditor.d.ts +11 -9
  15. package/lib/components/shared/BasicValueSpecificationEditor.d.ts.map +1 -1
  16. package/lib/components/shared/BasicValueSpecificationEditor.js +160 -143
  17. package/lib/components/shared/BasicValueSpecificationEditor.js.map +1 -1
  18. package/lib/index.css +2 -2
  19. package/lib/index.css.map +1 -1
  20. package/lib/package.json +1 -1
  21. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts +0 -1
  22. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.d.ts.map +1 -1
  23. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js +0 -8
  24. package/lib/stores/fetch-structure/tds/QueryBuilderTDSState.js.map +1 -1
  25. package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js +2 -2
  26. package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js.map +1 -1
  27. package/lib/stores/filter/QueryBuilderFilterState.d.ts +1 -1
  28. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  29. package/lib/stores/filter/QueryBuilderFilterState.js +4 -3
  30. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  31. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js +2 -2
  32. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js.map +1 -1
  33. package/lib/stores/milestoning/QueryBuilderMilestoningState.d.ts.map +1 -1
  34. package/lib/stores/milestoning/QueryBuilderMilestoningState.js +3 -9
  35. package/lib/stores/milestoning/QueryBuilderMilestoningState.js.map +1 -1
  36. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts +1 -0
  37. package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
  38. package/lib/stores/shared/ValueSpecificationEditorHelper.js +48 -0
  39. package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
  40. package/package.json +8 -8
  41. package/src/components/explorer/QueryBuilderMilestoningEditor.tsx +46 -60
  42. package/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx +3 -53
  43. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +19 -116
  44. package/src/components/filter/QueryBuilderFilterPanel.tsx +13 -5
  45. package/src/components/shared/BasicValueSpecificationEditor.tsx +299 -285
  46. package/src/stores/fetch-structure/tds/QueryBuilderTDSState.ts +0 -11
  47. package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.ts +2 -2
  48. package/src/stores/filter/QueryBuilderFilterState.ts +6 -3
  49. package/src/stores/filter/operators/QueryBuilderFilterOperator_In.ts +2 -2
  50. package/src/stores/milestoning/QueryBuilderMilestoningState.ts +7 -11
  51. package/src/stores/shared/ValueSpecificationEditorHelper.ts +63 -0
@@ -14,10 +14,14 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { useApplicationStore } from '@finos/legend-application';
17
+ import {
18
+ DEFAULT_TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH,
19
+ useApplicationStore,
20
+ } from '@finos/legend-application';
18
21
  import {
19
22
  type TooltipPlacement,
20
23
  type InputActionData,
24
+ type SelectActionData,
21
25
  Tooltip,
22
26
  DollarIcon,
23
27
  clsx,
@@ -29,9 +33,6 @@ import {
29
33
  SaveIcon,
30
34
  PencilIcon,
31
35
  DragPreviewLayer,
32
- FilledWindowMaximizeIcon,
33
- BasePopover,
34
- PanelFormSection,
35
36
  CalculateIcon,
36
37
  InputWithInlineValidation,
37
38
  } from '@finos/legend-art';
@@ -52,7 +53,6 @@ import {
52
53
  GenericTypeExplicitReference,
53
54
  GenericType,
54
55
  Enumeration,
55
- getEnumValue,
56
56
  getMultiplicityDescription,
57
57
  type ObserverContext,
58
58
  matchFunctionName,
@@ -63,16 +63,16 @@ import {
63
63
  type GeneratorFn,
64
64
  guaranteeNonNullable,
65
65
  isNonNullable,
66
- returnUndefOnError,
67
- uniq,
68
- parseCSVString,
69
66
  guaranteeIsNumber,
70
67
  csvStringify,
71
68
  guaranteeType,
69
+ isNonEmptyString,
70
+ parseCSVString,
71
+ uniq,
72
72
  } from '@finos/legend-shared';
73
73
  import { flowResult } from 'mobx';
74
74
  import { observer } from 'mobx-react-lite';
75
- import {
75
+ import React, {
76
76
  forwardRef,
77
77
  useEffect,
78
78
  useImperativeHandle,
@@ -91,6 +91,10 @@ import {
91
91
  } from '../../stores/QueryBuilderValueSpecificationHelper.js';
92
92
  import { evaluate } from 'mathjs';
93
93
  import { isUsedDateFunctionSupportedInFormMode } from '../../stores/QueryBuilderStateBuilder.js';
94
+ import {
95
+ convertTextToPrimitiveInstanceValue,
96
+ getValueSpecificationStringValue,
97
+ } from '../../stores/shared/ValueSpecificationEditorHelper.js';
94
98
 
95
99
  type TypeCheckOption = {
96
100
  expectedType: Type;
@@ -222,16 +226,7 @@ const StringPrimitiveInstanceValueEditor = observer(
222
226
  className?: string | undefined;
223
227
  setValueSpecification: (val: ValueSpecification) => void;
224
228
  resetValue: () => void;
225
- selectorConfig?:
226
- | {
227
- values: string[] | undefined;
228
- isLoading: boolean;
229
- reloadValues:
230
- | DebouncedFunc<(inputValue: string) => GeneratorFn<void>>
231
- | undefined;
232
- cleanUpReloadValues?: () => void;
233
- }
234
- | undefined;
229
+ selectorConfig?: BasicValueSpecificationEditorSelectorConfig | undefined;
235
230
  obseverContext: ObserverContext;
236
231
  }
237
232
  >(function StringPrimitiveInstanceValueEditor(props, ref) {
@@ -628,153 +623,287 @@ const stringifyValue = (values: ValueSpecification[]): string => {
628
623
  ]).trim();
629
624
  };
630
625
 
631
- /**
632
- * NOTE: We attempt to be less disruptive here by not throwing errors left and right, instead
633
- * we silently remove values which are not valid or parsable. But perhaps, we can consider
634
- * passing in logger or notifier to show give the users some idea of what went wrong instead
635
- * of silently swallow parts of their inputs like this.
636
- */
637
- const setCollectionValue = (
638
- valueSpecification: CollectionInstanceValue,
639
- expectedType: Type,
640
- value: string,
641
- obseverContext: ObserverContext,
642
- ): void => {
643
- if (value.trim().length === 0) {
644
- instanceValue_setValues(valueSpecification, [], obseverContext);
645
- return;
626
+ const getPlaceHolder = (expectedType: Type): string => {
627
+ if (expectedType instanceof PrimitiveType) {
628
+ switch (expectedType.path) {
629
+ case PRIMITIVE_TYPE.DATE:
630
+ case PRIMITIVE_TYPE.STRICTDATE:
631
+ return 'yyyy-mm-dd';
632
+ case PRIMITIVE_TYPE.DATETIME:
633
+ return 'yyyy-mm-ddThh:mm:ss';
634
+ default:
635
+ return 'Add';
636
+ }
646
637
  }
647
- let result: unknown[] = [];
638
+ return 'Add';
639
+ };
648
640
 
649
- const parseData = parseCSVString(value);
641
+ interface BasicValueSpecificationEditorSelectorConfig {
642
+ values: string[] | undefined;
643
+ isLoading: boolean;
644
+ reloadValues:
645
+ | DebouncedFunc<(inputValue: string) => GeneratorFn<void>>
646
+ | undefined;
647
+ cleanUpReloadValues?: () => void;
648
+ }
650
649
 
651
- if (!parseData) {
652
- return;
653
- }
650
+ const PrimitiveCollectionInstanceValueEditor = observer(
651
+ (props: {
652
+ valueSpecification: CollectionInstanceValue;
653
+ expectedType: Type;
654
+ saveEdit: () => void;
655
+ selectorConfig?: BasicValueSpecificationEditorSelectorConfig | undefined;
656
+ observerContext: ObserverContext;
657
+ }) => {
658
+ const {
659
+ valueSpecification,
660
+ expectedType,
661
+ saveEdit,
662
+ selectorConfig,
663
+ observerContext,
664
+ } = props;
654
665
 
655
- if (expectedType instanceof PrimitiveType) {
656
- switch (expectedType.path) {
657
- case PRIMITIVE_TYPE.STRING: {
658
- result = uniq(parseData)
659
- .map((item): PrimitiveInstanceValue | undefined => {
660
- const primitiveInstanceValue = new PrimitiveInstanceValue(
661
- GenericTypeExplicitReference.create(
662
- new GenericType(expectedType),
663
- ),
664
- );
665
- instanceValue_setValues(
666
- primitiveInstanceValue,
667
- [item.toString()],
668
- obseverContext,
669
- );
670
- return primitiveInstanceValue;
671
- })
672
- .filter(isNonNullable);
673
- break;
666
+ // local state and variables
667
+ const applicationStore = useApplicationStore();
668
+ const inputRef = useRef(null);
669
+ const [inputValue, setInputValue] = useState('');
670
+ const [inputValueIsError, setInputValueIsError] = useState(false);
671
+ const [selectedOptions, setSelectedOptions] = useState<
672
+ { label: string; value: string }[]
673
+ >(
674
+ valueSpecification.values
675
+ .map((valueSpec) => getValueSpecificationStringValue(valueSpec))
676
+ .filter(isNonEmptyString)
677
+ .map((value) => ({
678
+ label: value,
679
+ value,
680
+ })),
681
+ );
682
+
683
+ // typehead search setup
684
+ const isTypeaheadSearchEnabled =
685
+ expectedType === PrimitiveType.STRING && Boolean(selectorConfig);
686
+ const reloadValuesFunc = isTypeaheadSearchEnabled
687
+ ? selectorConfig?.reloadValues
688
+ : undefined;
689
+ const cleanUpReloadValuesFunc = isTypeaheadSearchEnabled
690
+ ? selectorConfig?.cleanUpReloadValues
691
+ : undefined;
692
+ const isLoading = isTypeaheadSearchEnabled
693
+ ? selectorConfig?.isLoading
694
+ : undefined;
695
+ const queryOptions =
696
+ isTypeaheadSearchEnabled && selectorConfig?.values?.length
697
+ ? selectorConfig.values.map((e) => ({
698
+ value: e,
699
+ label: e.toString(),
700
+ }))
701
+ : undefined;
702
+ const noMatchMessage =
703
+ isTypeaheadSearchEnabled && isLoading ? 'Loading...' : undefined;
704
+
705
+ // helper functions
706
+ const buildOptionForValueSpec = (
707
+ value: ValueSpecification,
708
+ ): { label: string; value: string } => {
709
+ const stringValue = guaranteeNonNullable(
710
+ getValueSpecificationStringValue(value),
711
+ );
712
+ return {
713
+ label: stringValue,
714
+ value: stringValue,
715
+ };
716
+ };
717
+
718
+ const isValueAlreadySelected = (value: string): boolean =>
719
+ selectedOptions.map((option) => option.value).includes(value);
720
+
721
+ /**
722
+ * NOTE: We attempt to be less disruptive here by not throwing errors left and right, instead
723
+ * we simply return null for values which are not valid or parsable. But perhaps, we can consider
724
+ * passing in logger or notifier to give the users some idea of what went wrong instead of ignoring
725
+ * their input.
726
+ */
727
+ const convertInputValueToValueSpec = (): ValueSpecification | null => {
728
+ const trimmedInputValue = inputValue.trim();
729
+
730
+ if (trimmedInputValue.length) {
731
+ const newValueSpec = convertTextToPrimitiveInstanceValue(
732
+ expectedType,
733
+ trimmedInputValue,
734
+ observerContext,
735
+ );
736
+
737
+ if (
738
+ newValueSpec === null ||
739
+ getValueSpecificationStringValue(newValueSpec) === undefined ||
740
+ isValueAlreadySelected(
741
+ guaranteeNonNullable(
742
+ getValueSpecificationStringValue(newValueSpec),
743
+ ),
744
+ )
745
+ ) {
746
+ return null;
747
+ }
748
+
749
+ return newValueSpec;
674
750
  }
675
- case PRIMITIVE_TYPE.NUMBER:
676
- case PRIMITIVE_TYPE.FLOAT:
677
- case PRIMITIVE_TYPE.DECIMAL:
678
- case PRIMITIVE_TYPE.INTEGER: {
679
- result = uniq(
680
- parseData
681
- .filter((val) => !isNaN(Number(val)))
682
- .map((val) => Number(val)),
683
- )
684
- .map((item): PrimitiveInstanceValue | undefined => {
685
- const primitiveInstanceValue = new PrimitiveInstanceValue(
686
- GenericTypeExplicitReference.create(
687
- new GenericType(expectedType),
688
- ),
689
- );
690
- instanceValue_setValues(
691
- primitiveInstanceValue,
692
- [item],
693
- obseverContext,
694
- );
695
- return primitiveInstanceValue;
696
- })
697
- .filter(isNonNullable);
698
- break;
751
+ return null;
752
+ };
753
+
754
+ const addInputValueToSelectedOptions = (): void => {
755
+ const newValueSpec = convertInputValueToValueSpec();
756
+
757
+ if (newValueSpec !== null) {
758
+ setSelectedOptions([
759
+ ...selectedOptions,
760
+ buildOptionForValueSpec(newValueSpec),
761
+ ]);
762
+ setInputValue('');
763
+ reloadValuesFunc?.cancel();
764
+ } else if (inputValue.trim().length) {
765
+ setInputValueIsError(true);
699
766
  }
700
- case PRIMITIVE_TYPE.DATE:
701
- case PRIMITIVE_TYPE.STRICTDATE: {
702
- result = uniq(
703
- parseData
704
- .filter((val) => !isNaN(Date.parse(val)))
705
- .map((val) => val.trim()),
706
- )
707
- .map((item): PrimitiveInstanceValue | undefined => {
708
- const primitiveInstanceValue = new PrimitiveInstanceValue(
709
- GenericTypeExplicitReference.create(
710
- new GenericType(expectedType),
711
- ),
712
- );
713
- instanceValue_setValues(
714
- primitiveInstanceValue,
715
- [item],
716
- obseverContext,
717
- );
718
- return primitiveInstanceValue;
719
- })
720
- .filter(isNonNullable);
721
- break;
767
+ };
768
+
769
+ // event handlers
770
+ const changeValue = (
771
+ newSelectedOptions: { value: string; label: string }[],
772
+ actionChange: SelectActionData<{ value: string; label: string }>,
773
+ ): void => {
774
+ setSelectedOptions(newSelectedOptions);
775
+ if (actionChange.action === 'select-option') {
776
+ setInputValue('');
777
+ } else if (
778
+ actionChange.action === 'remove-value' &&
779
+ actionChange.removedValue.value === inputValue
780
+ ) {
781
+ setInputValueIsError(false);
722
782
  }
723
- case PRIMITIVE_TYPE.DATETIME: {
724
- result = uniq(
725
- parseData
726
- .filter(
727
- (val) =>
728
- (!isNaN(Date.parse(val)) && new Date(val).getTime()) ||
729
- (val.includes('%') &&
730
- !isNaN(Date.parse(val.slice(1))) &&
731
- new Date(val.slice(1)).getTime()),
732
- )
733
- .map((val) => val.trim()),
734
- )
735
- .map((item): PrimitiveInstanceValue | undefined => {
736
- const primitiveInstanceValue = new PrimitiveInstanceValue(
737
- GenericTypeExplicitReference.create(
738
- new GenericType(expectedType),
739
- ),
740
- );
741
- instanceValue_setValues(
742
- primitiveInstanceValue,
743
- [item],
744
- obseverContext,
745
- );
746
- return primitiveInstanceValue;
747
- })
748
- .filter(isNonNullable);
749
- break;
783
+ };
784
+
785
+ const handleInputChange = (
786
+ newInputValue: string,
787
+ actionChange: InputActionData,
788
+ ): void => {
789
+ if (actionChange.action === 'input-change') {
790
+ setInputValue(newInputValue);
791
+ setInputValueIsError(false);
792
+ reloadValuesFunc?.cancel();
793
+ const reloadValuesFuncTransformation =
794
+ reloadValuesFunc?.(newInputValue);
795
+ if (reloadValuesFuncTransformation) {
796
+ flowResult(reloadValuesFuncTransformation).catch(
797
+ applicationStore.alertUnhandledError,
798
+ );
799
+ }
750
800
  }
751
- default:
752
- // unsupported expected type, just escape
801
+ if (actionChange.action === 'input-blur') {
802
+ reloadValuesFunc?.cancel();
803
+ cleanUpReloadValuesFunc?.();
804
+ }
805
+ };
806
+
807
+ const updateValueSpecAndSaveEdit = (): void => {
808
+ const newValueSpec = convertInputValueToValueSpec();
809
+ const finalSelectedOptions =
810
+ newValueSpec !== null
811
+ ? [...selectedOptions, buildOptionForValueSpec(newValueSpec)]
812
+ : selectedOptions;
813
+ instanceValue_setValues(
814
+ valueSpecification,
815
+ finalSelectedOptions
816
+ .map((option) => option.value)
817
+ .map((value) =>
818
+ convertTextToPrimitiveInstanceValue(
819
+ expectedType,
820
+ value,
821
+ observerContext,
822
+ ),
823
+ )
824
+ .filter(isNonNullable),
825
+ observerContext,
826
+ );
827
+ saveEdit();
828
+ };
829
+
830
+ const handleKeyDown = (event: KeyboardEvent): void => {
831
+ if ((event.key === 'Enter' || event.key === ',') && !event.shiftKey) {
832
+ addInputValueToSelectedOptions();
833
+ event.preventDefault();
834
+ }
835
+ };
836
+
837
+ const handlePaste = (event: React.ClipboardEvent<string>): void => {
838
+ const pastedText = event.clipboardData.getData('text');
839
+ const parsedData = parseCSVString(pastedText);
840
+ if (!parsedData) {
753
841
  return;
754
- }
755
- } else if (expectedType instanceof Enumeration) {
756
- result = uniq(parseData.map((item) => item.trim()))
757
- .map((item): EnumValueInstanceValue | undefined => {
758
- const _enum = returnUndefOnError(() =>
759
- getEnumValue(expectedType, item),
760
- );
761
- if (!_enum) {
762
- return undefined;
763
- }
764
- const enumValueInstanceValue = new EnumValueInstanceValue(
765
- GenericTypeExplicitReference.create(new GenericType(expectedType)),
766
- );
767
- instanceValue_setValues(
768
- enumValueInstanceValue,
769
- [EnumValueExplicitReference.create(_enum)],
770
- obseverContext,
771
- );
772
- return enumValueInstanceValue;
773
- })
774
- .filter(isNonNullable);
775
- }
776
- instanceValue_setValues(valueSpecification, result, obseverContext);
777
- };
842
+ }
843
+ const newValues = uniq(
844
+ uniq(parsedData)
845
+ .map((value) => {
846
+ const newValueSpec = convertTextToPrimitiveInstanceValue(
847
+ expectedType,
848
+ value,
849
+ observerContext,
850
+ );
851
+ return newValueSpec
852
+ ? getValueSpecificationStringValue(newValueSpec)
853
+ : null;
854
+ })
855
+ .filter(isNonNullable),
856
+ ).filter((value) => !isValueAlreadySelected(value));
857
+ setSelectedOptions([
858
+ ...selectedOptions,
859
+ ...newValues.map((value) => ({ label: value, value })),
860
+ ]);
861
+ event.preventDefault();
862
+ };
863
+
864
+ return (
865
+ <>
866
+ <CustomSelectorInput
867
+ className={clsx('value-spec-editor__primitive-collection-selector', {
868
+ 'value-spec-editor__primitive-collection-selector--error':
869
+ inputValueIsError,
870
+ })}
871
+ options={queryOptions}
872
+ inputValue={inputValue}
873
+ isMulti={true}
874
+ menuIsOpen={
875
+ isTypeaheadSearchEnabled &&
876
+ inputValue.length >= DEFAULT_TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH
877
+ }
878
+ autoFocus={true}
879
+ inputRef={inputRef}
880
+ onChange={changeValue}
881
+ onInputChange={handleInputChange}
882
+ onBlur={() => updateValueSpecAndSaveEdit()}
883
+ onKeyDown={handleKeyDown}
884
+ onPaste={handlePaste}
885
+ value={selectedOptions}
886
+ darkMode={
887
+ !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
888
+ }
889
+ isLoading={isLoading}
890
+ noMatchMessage={noMatchMessage}
891
+ placeholder={null}
892
+ inputPlaceholder={getPlaceHolder(expectedType)}
893
+ components={{
894
+ DropdownIndicator: null,
895
+ }}
896
+ />
897
+ <button
898
+ className="value-spec-editor__list-editor__save-button btn--dark"
899
+ onClick={updateValueSpecAndSaveEdit}
900
+ >
901
+ <SaveIcon />
902
+ </button>
903
+ </>
904
+ );
905
+ },
906
+ );
778
907
 
779
908
  const EnumCollectionInstanceValueEditor = observer(
780
909
  (props: {
@@ -853,7 +982,8 @@ const EnumCollectionInstanceValueEditor = observer(
853
982
  darkMode={
854
983
  !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
855
984
  }
856
- placeholder="Select value"
985
+ placeholder={null}
986
+ inputPlaceholder="Add"
857
987
  autoFocus={true}
858
988
  menuIsOpen={true}
859
989
  />
@@ -870,21 +1000,6 @@ const EnumCollectionInstanceValueEditor = observer(
870
1000
 
871
1001
  const COLLECTION_PREVIEW_CHAR_LIMIT = 50;
872
1002
 
873
- const getPlaceHolder = (expectedType: Type): string => {
874
- if (expectedType instanceof PrimitiveType) {
875
- switch (expectedType.path) {
876
- case PRIMITIVE_TYPE.DATE:
877
- case PRIMITIVE_TYPE.STRICTDATE:
878
- return 'yyyy-mm-dd';
879
- case PRIMITIVE_TYPE.DATETIME:
880
- return 'yyyy-mm-ddThh:mm:ss';
881
- default:
882
- return '(empty)';
883
- }
884
- }
885
- return '(empty)';
886
- };
887
-
888
1003
  const CollectionValueInstanceValueEditor = observer(
889
1004
  (props: {
890
1005
  valueSpecification: CollectionInstanceValue;
@@ -893,6 +1008,7 @@ const CollectionValueInstanceValueEditor = observer(
893
1008
  className?: string | undefined;
894
1009
  resetValue: () => void;
895
1010
  setValueSpecification: (val: ValueSpecification) => void;
1011
+ selectorConfig?: BasicValueSpecificationEditorSelectorConfig | undefined;
896
1012
  obseverContext: ObserverContext;
897
1013
  }) => {
898
1014
  const {
@@ -901,14 +1017,11 @@ const CollectionValueInstanceValueEditor = observer(
901
1017
  className,
902
1018
  resetValue,
903
1019
  setValueSpecification,
1020
+ selectorConfig,
904
1021
  obseverContext,
905
1022
  } = props;
906
- const inputRef = useRef<HTMLTextAreaElement>(null);
907
1023
 
908
- const [text, setText] = useState(stringifyValue(valueSpecification.values));
909
1024
  const [editable, setEditable] = useState(false);
910
- const [showAdvancedEditorPopover, setShowAdvancedEditorPopover] =
911
- useState(false);
912
1025
  const valueText = stringifyValue(valueSpecification.values);
913
1026
  const previewText = `List(${
914
1027
  valueSpecification.values.length === 0
@@ -927,78 +1040,13 @@ const CollectionValueInstanceValueEditor = observer(
927
1040
  const saveEdit = (): void => {
928
1041
  if (editable) {
929
1042
  setEditable(false);
930
- setShowAdvancedEditorPopover(false);
931
1043
  setValueSpecification(valueSpecification);
932
1044
  }
933
1045
  };
934
- const updateValueSpecAndSaveEdit = (): void => {
935
- if (editable) {
936
- setCollectionValue(
937
- valueSpecification,
938
- expectedType,
939
- text,
940
- obseverContext,
941
- );
942
- setText(stringifyValue(valueSpecification.values));
943
- saveEdit();
944
- }
945
- };
946
-
947
- const changeValueTextArea: React.ChangeEventHandler<HTMLTextAreaElement> = (
948
- event,
949
- ) => {
950
- setText(event.target.value);
951
- };
952
- const expandButtonName = `${valueSpecification.hashCode}ExpandButton`;
953
- const handleOnBlur: React.FocusEventHandler<HTMLTextAreaElement> = (
954
- event,
955
- ) => {
956
- // disable save if target is expand button
957
- if (
958
- (event.relatedTarget as HTMLButtonElement | undefined)?.name !==
959
- expandButtonName
960
- ) {
961
- updateValueSpecAndSaveEdit();
962
- }
963
- };
964
-
965
- const placeholder = text === '' ? getPlaceHolder(expectedType) : undefined;
966
-
967
- // focus the input box when edit is enabled
968
- useEffect(() => {
969
- if (editable) {
970
- inputRef.current?.focus();
971
- }
972
- }, [editable]);
973
1046
 
974
1047
  if (editable) {
975
1048
  return (
976
1049
  <>
977
- {showAdvancedEditorPopover && (
978
- <BasePopover
979
- onClose={() => setShowAdvancedEditorPopover(false)}
980
- open={showAdvancedEditorPopover}
981
- anchorEl={inputRef.current}
982
- >
983
- <textarea
984
- className="panel__content__form__section__input value-spec-editor__list-editor__textarea"
985
- spellCheck={false}
986
- value={text}
987
- placeholder={placeholder}
988
- onChange={changeValueTextArea}
989
- onKeyDown={(event): void => {
990
- if (event.key === 'Enter' && !event.shiftKey) {
991
- updateValueSpecAndSaveEdit();
992
- }
993
- }}
994
- />
995
- <PanelFormSection>
996
- <div className="value-spec-editor__list-editor__textarea__description">
997
- Hit Enter to Apply Change
998
- </div>
999
- </PanelFormSection>
1000
- </BasePopover>
1001
- )}
1002
1050
  <div className={clsx('value-spec-editor', className)}>
1003
1051
  {expectedType instanceof Enumeration ? (
1004
1052
  <EnumCollectionInstanceValueEditor
@@ -1007,39 +1055,13 @@ const CollectionValueInstanceValueEditor = observer(
1007
1055
  saveEdit={saveEdit}
1008
1056
  />
1009
1057
  ) : (
1010
- <>
1011
- <textarea
1012
- ref={inputRef}
1013
- className={clsx(
1014
- 'panel__content__form__section__input value-spec-editor__input value-spec-editor__textarea ',
1015
- )}
1016
- spellCheck={false}
1017
- value={text}
1018
- placeholder={placeholder}
1019
- onChange={changeValueTextArea}
1020
- onKeyDown={(event): void => {
1021
- if (event.key === 'Enter' && !event.shiftKey) {
1022
- updateValueSpecAndSaveEdit();
1023
- }
1024
- }}
1025
- onBlur={handleOnBlur}
1026
- />
1027
- <button
1028
- className="value-spec-editor__list-editor__expand-button btn--dark"
1029
- onClick={() => setShowAdvancedEditorPopover(true)}
1030
- tabIndex={-1}
1031
- name={expandButtonName}
1032
- title="Expand window..."
1033
- >
1034
- <FilledWindowMaximizeIcon />
1035
- </button>
1036
- <button
1037
- className="value-spec-editor__list-editor__save-button btn--dark"
1038
- onClick={saveEdit}
1039
- >
1040
- <SaveIcon />
1041
- </button>
1042
- </>
1058
+ <PrimitiveCollectionInstanceValueEditor
1059
+ valueSpecification={valueSpecification}
1060
+ expectedType={expectedType}
1061
+ saveEdit={saveEdit}
1062
+ selectorConfig={selectorConfig}
1063
+ observerContext={obseverContext}
1064
+ />
1043
1065
  )}
1044
1066
  <button
1045
1067
  className="value-spec-editor__reset-btn"
@@ -1141,16 +1163,7 @@ export const BasicValueSpecificationEditor = forwardRef<
1141
1163
  setValueSpecification: (val: ValueSpecification) => void;
1142
1164
  resetValue: () => void;
1143
1165
  isConstant?: boolean;
1144
- selectorConfig?:
1145
- | {
1146
- values: string[] | undefined;
1147
- isLoading: boolean;
1148
- reloadValues:
1149
- | DebouncedFunc<(inputValue: string) => GeneratorFn<void>>
1150
- | undefined;
1151
- cleanUpReloadValues?: () => void;
1152
- }
1153
- | undefined;
1166
+ selectorConfig?: BasicValueSpecificationEditorSelectorConfig | undefined;
1154
1167
  }
1155
1168
  >(function BasicValueSpecificationEditor(props, ref) {
1156
1169
  const {
@@ -1249,6 +1262,7 @@ export const BasicValueSpecificationEditor = forwardRef<
1249
1262
  className={className}
1250
1263
  resetValue={resetValue}
1251
1264
  setValueSpecification={setValueSpecification}
1265
+ selectorConfig={selectorConfig}
1252
1266
  obseverContext={obseverContext}
1253
1267
  />
1254
1268
  );