@finos/legend-application 3.0.3 → 4.0.2

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 (176) hide show
  1. package/lib/application/LegendApplication.d.ts +2 -2
  2. package/lib/application/LegendApplication.d.ts.map +1 -1
  3. package/lib/application/LegendApplication.js +4 -4
  4. package/lib/application/LegendApplication.js.map +1 -1
  5. package/lib/application/LegendApplicationPluginManager.d.ts +3 -3
  6. package/lib/application/LegendApplicationPluginManager.d.ts.map +1 -1
  7. package/lib/components/ActionAlert.d.ts +1 -0
  8. package/lib/components/ActionAlert.d.ts.map +1 -1
  9. package/lib/components/ActionAlert.js +2 -2
  10. package/lib/components/ActionAlert.js.map +1 -1
  11. package/lib/components/ApplicationStoreProvider.d.ts +3 -3
  12. package/lib/components/ApplicationStoreProvider.d.ts.map +1 -1
  13. package/lib/components/ApplicationStoreProvider.js +2 -2
  14. package/lib/components/ApplicationStoreProvider.js.map +1 -1
  15. package/lib/components/ApplicationStoreProviderTestUtils.d.ts +5 -5
  16. package/lib/components/ApplicationStoreProviderTestUtils.d.ts.map +1 -1
  17. package/lib/components/ApplicationStoreProviderTestUtils.js +5 -4
  18. package/lib/components/ApplicationStoreProviderTestUtils.js.map +1 -1
  19. package/lib/components/ApplicationTestID.js +1 -1
  20. package/lib/components/ApplicationTestID.js.map +1 -1
  21. package/lib/components/BasicValueSpecificationEditor.d.ts +44 -0
  22. package/lib/components/BasicValueSpecificationEditor.d.ts.map +1 -0
  23. package/lib/components/BasicValueSpecificationEditor.js +276 -0
  24. package/lib/components/BasicValueSpecificationEditor.js.map +1 -0
  25. package/lib/components/BlockingAlert.d.ts +1 -0
  26. package/lib/components/BlockingAlert.d.ts.map +1 -1
  27. package/lib/components/BlockingAlert.js +1 -1
  28. package/lib/components/BlockingAlert.js.map +1 -1
  29. package/lib/components/CustomDatePicker.d.ts +38 -0
  30. package/lib/components/CustomDatePicker.d.ts.map +1 -0
  31. package/lib/components/CustomDatePicker.js +592 -0
  32. package/lib/components/CustomDatePicker.js.map +1 -0
  33. package/lib/components/DocumentationLink.d.ts +1 -1
  34. package/lib/components/DocumentationLink.js +2 -2
  35. package/lib/components/DocumentationLink.js.map +1 -1
  36. package/lib/components/LambdaEditor.d.ts +2 -1
  37. package/lib/components/LambdaEditor.d.ts.map +1 -1
  38. package/lib/components/LambdaEditor.js +3 -3
  39. package/lib/components/LambdaEditor.js.map +1 -1
  40. package/lib/components/LambdaParameterValuesEditor.d.ts +25 -0
  41. package/lib/components/LambdaParameterValuesEditor.d.ts.map +1 -0
  42. package/lib/components/LambdaParameterValuesEditor.js +52 -0
  43. package/lib/components/LambdaParameterValuesEditor.js.map +1 -0
  44. package/lib/components/LegendApplicationComponentFrameworkProvider.d.ts +1 -1
  45. package/lib/components/LegendApplicationComponentFrameworkProvider.js +3 -3
  46. package/lib/components/LegendApplicationComponentFrameworkProvider.js.map +1 -1
  47. package/lib/components/LegendApplicationNavigationContextServiceUtils.d.ts +32 -0
  48. package/lib/components/LegendApplicationNavigationContextServiceUtils.d.ts.map +1 -0
  49. package/lib/components/LegendApplicationNavigationContextServiceUtils.js +57 -0
  50. package/lib/components/LegendApplicationNavigationContextServiceUtils.js.map +1 -0
  51. package/lib/components/NotificationManager.d.ts +1 -0
  52. package/lib/components/NotificationManager.d.ts.map +1 -1
  53. package/lib/components/NotificationManager.js +2 -2
  54. package/lib/components/NotificationManager.js.map +1 -1
  55. package/lib/components/TextInputEditor.d.ts +2 -2
  56. package/lib/components/TextInputEditor.d.ts.map +1 -1
  57. package/lib/components/TextInputEditor.js +2 -2
  58. package/lib/components/TextInputEditor.js.map +1 -1
  59. package/lib/components/{AppHeader.d.ts → VirtualAssistant.d.ts} +5 -5
  60. package/lib/components/VirtualAssistant.d.ts.map +1 -0
  61. package/lib/components/VirtualAssistant.js +171 -0
  62. package/lib/components/VirtualAssistant.js.map +1 -0
  63. package/lib/components/WebApplicationNavigatorProvider.d.ts +2 -2
  64. package/lib/components/WebApplicationNavigatorProvider.d.ts.map +1 -1
  65. package/lib/components/WebApplicationNavigatorProvider.js +1 -1
  66. package/lib/components/WebApplicationNavigatorProvider.js.map +1 -1
  67. package/lib/components/WebApplicationNavigatorProviderTestUtils.d.ts +2 -2
  68. package/lib/components/WebApplicationNavigatorProviderTestUtils.d.ts.map +1 -1
  69. package/lib/components/WebApplicationNavigatorProviderTestUtils.js +3 -2
  70. package/lib/components/WebApplicationNavigatorProviderTestUtils.js.map +1 -1
  71. package/lib/const.js +2 -2
  72. package/lib/const.js.map +1 -1
  73. package/lib/index.css +2 -2
  74. package/lib/index.css.map +1 -1
  75. package/lib/index.d.ts +30 -22
  76. package/lib/index.d.ts.map +1 -1
  77. package/lib/index.js +32 -22
  78. package/lib/index.js.map +1 -1
  79. package/lib/stores/ApplicationEvent.d.ts +9 -7
  80. package/lib/stores/ApplicationEvent.d.ts.map +1 -1
  81. package/lib/stores/ApplicationEvent.js +10 -8
  82. package/lib/stores/ApplicationEvent.js.map +1 -1
  83. package/lib/stores/ApplicationStore.d.ts +15 -9
  84. package/lib/stores/ApplicationStore.d.ts.map +1 -1
  85. package/lib/stores/ApplicationStore.js +26 -21
  86. package/lib/stores/ApplicationStore.js.map +1 -1
  87. package/lib/stores/ApplicationStoreTestUtils.d.ts +3 -3
  88. package/lib/stores/ApplicationStoreTestUtils.d.ts.map +1 -1
  89. package/lib/stores/ApplicationStoreTestUtils.js +2 -2
  90. package/lib/stores/ApplicationStoreTestUtils.js.map +1 -1
  91. package/lib/stores/ApplicationTelemetry.d.ts +1 -1
  92. package/lib/stores/ApplicationTelemetry.d.ts.map +1 -1
  93. package/lib/stores/ApplicationTelemetry.js +2 -2
  94. package/lib/stores/ApplicationTelemetry.js.map +1 -1
  95. package/lib/stores/CJS__Fuse.cjs +35 -0
  96. package/lib/stores/CJS__Fuse.cjs.map +1 -0
  97. package/lib/stores/CJS__Fuse.d.cts +28 -0
  98. package/lib/stores/CJS__Fuse.d.cts.map +1 -0
  99. package/lib/stores/LambdaParameterState.d.ts +59 -0
  100. package/lib/stores/LambdaParameterState.d.ts.map +1 -0
  101. package/lib/stores/LambdaParameterState.js +184 -0
  102. package/lib/stores/LambdaParameterState.js.map +1 -0
  103. package/lib/stores/LegendApplicationAssistantService.d.ts +63 -0
  104. package/lib/stores/LegendApplicationAssistantService.d.ts.map +1 -0
  105. package/lib/stores/LegendApplicationAssistantService.js +167 -0
  106. package/lib/stores/LegendApplicationAssistantService.js.map +1 -0
  107. package/lib/stores/LegendApplicationConfig.d.ts +5 -4
  108. package/lib/stores/LegendApplicationConfig.d.ts.map +1 -1
  109. package/lib/stores/LegendApplicationConfig.js +8 -3
  110. package/lib/stores/LegendApplicationConfig.js.map +1 -1
  111. package/lib/stores/LegendApplicationDocumentationService.d.ts +70 -0
  112. package/lib/stores/LegendApplicationDocumentationService.d.ts.map +1 -0
  113. package/lib/stores/LegendApplicationDocumentationService.js +152 -0
  114. package/lib/stores/LegendApplicationDocumentationService.js.map +1 -0
  115. package/lib/stores/LegendApplicationEventService.d.ts +22 -0
  116. package/lib/stores/LegendApplicationEventService.d.ts.map +1 -0
  117. package/lib/stores/LegendApplicationEventService.js +25 -0
  118. package/lib/stores/LegendApplicationEventService.js.map +1 -0
  119. package/lib/stores/LegendApplicationNavigationContextService.d.ts +74 -0
  120. package/lib/stores/LegendApplicationNavigationContextService.d.ts.map +1 -0
  121. package/lib/stores/LegendApplicationNavigationContextService.js +118 -0
  122. package/lib/stores/LegendApplicationNavigationContextService.js.map +1 -0
  123. package/lib/stores/LegendApplicationPlugin.d.ts +6 -2
  124. package/lib/stores/LegendApplicationPlugin.d.ts.map +1 -1
  125. package/lib/stores/LegendApplicationPlugin.js.map +1 -1
  126. package/lib/stores/PureLanguageSupport.d.ts.map +1 -1
  127. package/lib/stores/PureLanguageSupport.js +8 -2
  128. package/lib/stores/PureLanguageSupport.js.map +1 -1
  129. package/lib/stores/ValueSpecificationModifierHelper.d.ts +27 -0
  130. package/lib/stores/ValueSpecificationModifierHelper.d.ts.map +1 -0
  131. package/lib/stores/ValueSpecificationModifierHelper.js +49 -0
  132. package/lib/stores/ValueSpecificationModifierHelper.js.map +1 -0
  133. package/package.json +24 -18
  134. package/src/application/LegendApplication.tsx +6 -6
  135. package/src/application/LegendApplicationPluginManager.tsx +3 -3
  136. package/src/components/ActionAlert.tsx +2 -2
  137. package/src/components/ApplicationStoreProvider.tsx +4 -4
  138. package/src/components/ApplicationStoreProviderTestUtils.tsx +7 -6
  139. package/src/components/BasicValueSpecificationEditor.tsx +703 -0
  140. package/src/components/BlockingAlert.tsx +1 -1
  141. package/src/components/CustomDatePicker.tsx +1235 -0
  142. package/src/components/DocumentationLink.tsx +2 -2
  143. package/src/components/LambdaEditor.tsx +4 -4
  144. package/src/components/LambdaParameterValuesEditor.tsx +114 -0
  145. package/src/components/LegendApplicationComponentFrameworkProvider.tsx +3 -3
  146. package/src/components/LegendApplicationNavigationContextServiceUtils.tsx +63 -0
  147. package/src/components/NotificationManager.tsx +2 -2
  148. package/src/components/TextInputEditor.tsx +2 -2
  149. package/src/components/VirtualAssistant.tsx +600 -0
  150. package/src/components/WebApplicationNavigatorProvider.tsx +1 -1
  151. package/src/components/WebApplicationNavigatorProviderTestUtils.tsx +3 -2
  152. package/src/index.ts +39 -28
  153. package/src/stores/ApplicationEvent.ts +11 -7
  154. package/src/stores/ApplicationStore.ts +29 -27
  155. package/src/stores/ApplicationStoreTestUtils.ts +4 -4
  156. package/src/stores/ApplicationTelemetry.ts +2 -2
  157. package/src/stores/CJS__Fuse.cts +28 -0
  158. package/src/stores/LambdaParameterState.ts +314 -0
  159. package/src/stores/LegendApplicationAssistantService.ts +218 -0
  160. package/src/stores/LegendApplicationConfig.ts +20 -6
  161. package/src/stores/LegendApplicationDocumentationService.ts +276 -0
  162. package/src/stores/LegendApplicationEventService.ts +32 -0
  163. package/src/stores/LegendApplicationNavigationContextService.ts +131 -0
  164. package/src/stores/LegendApplicationPlugin.ts +10 -2
  165. package/src/stores/PureLanguageSupport.ts +8 -2
  166. package/src/stores/ValueSpecificationModifierHelper.ts +104 -0
  167. package/tsconfig.json +18 -12
  168. package/lib/components/AppHeader.d.ts.map +0 -1
  169. package/lib/components/AppHeader.js +0 -26
  170. package/lib/components/AppHeader.js.map +0 -1
  171. package/lib/stores/LegendApplicationDocumentationRegistry.d.ts +0 -36
  172. package/lib/stores/LegendApplicationDocumentationRegistry.d.ts.map +0 -1
  173. package/lib/stores/LegendApplicationDocumentationRegistry.js +0 -47
  174. package/lib/stores/LegendApplicationDocumentationRegistry.js.map +0 -1
  175. package/src/components/AppHeader.tsx +0 -49
  176. package/src/stores/LegendApplicationDocumentationRegistry.ts +0 -81
@@ -0,0 +1,703 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ type TooltipPlacement,
19
+ Tooltip,
20
+ DollarIcon,
21
+ clsx,
22
+ InfoCircleIcon,
23
+ RefreshIcon,
24
+ CheckSquareIcon,
25
+ SquareIcon,
26
+ CustomSelectorInput,
27
+ SaveIcon,
28
+ PencilIcon,
29
+ } from '@finos/legend-art';
30
+ import {
31
+ type Enum,
32
+ type Type,
33
+ type ValueSpecification,
34
+ type PureModel,
35
+ PrimitiveInstanceValue,
36
+ CollectionInstanceValue,
37
+ EnumValueInstanceValue,
38
+ INTERNAL__PropagatedValue,
39
+ SimpleFunctionExpression,
40
+ VariableExpression,
41
+ EnumValueExplicitReference,
42
+ TYPICAL_MULTIPLICITY_TYPE,
43
+ PrimitiveType,
44
+ PRIMITIVE_TYPE,
45
+ GenericTypeExplicitReference,
46
+ GenericType,
47
+ Enumeration,
48
+ getEnumValue,
49
+ getMultiplicityDescription,
50
+ } from '@finos/legend-graph';
51
+ import {
52
+ guaranteeNonNullable,
53
+ isNonNullable,
54
+ returnUndefOnError,
55
+ uniq,
56
+ } from '@finos/legend-shared';
57
+ import { observer } from 'mobx-react-lite';
58
+ import CSVParser from 'papaparse';
59
+ import { useEffect, useRef, useState } from 'react';
60
+ import {
61
+ instanceValue_changeValue,
62
+ instanceValue_changeValues,
63
+ } from '../stores/ValueSpecificationModifierHelper.js';
64
+ import { CustomDatePicker } from './CustomDatePicker.js';
65
+
66
+ type TypeCheckOption = {
67
+ expectedType: Type;
68
+ /**
69
+ * Indicates if a strict type-matching will happen.
70
+ * Sometimes, auto-boxing allow some rooms to wiggle,
71
+ * for example we can assign a Float to an Integer, a
72
+ * Date to a DateTime. With this flag set to `true`
73
+ * we will not allow this.
74
+ */
75
+ match?: boolean;
76
+ };
77
+
78
+ const ParameterInfoTooltip: React.FC<{
79
+ variable: VariableExpression;
80
+ children: React.ReactElement;
81
+ placement?: TooltipPlacement | undefined;
82
+ }> = (props) => {
83
+ const { variable, children, placement } = props;
84
+ const type = variable.genericType?.value.rawType;
85
+ return (
86
+ <Tooltip
87
+ arrow={true}
88
+ {...(placement !== undefined ? { placement } : {})}
89
+ classes={{
90
+ tooltip: 'value-spec-paramater__tooltip',
91
+ arrow: 'value-spec-paramater__tooltip__arrow',
92
+ tooltipPlacementRight: 'value-spec-paramater__tooltip--right',
93
+ }}
94
+ TransitionProps={{
95
+ // disable transition
96
+ // NOTE: somehow, this is the only workaround we have, if for example
97
+ // we set `appear = true`, the tooltip will jump out of position
98
+ timeout: 0,
99
+ }}
100
+ title={
101
+ <div className="value-spec-paramater__tooltip__content">
102
+ <div className="value-spec-paramater__tooltip__item">
103
+ <div className="value-spec-paramater__tooltip__item__label">
104
+ Type
105
+ </div>
106
+ <div className="value-spec-paramater__tooltip__item__value">
107
+ {type?.name ?? ''}
108
+ </div>
109
+ </div>
110
+ <div className="value-spec-paramater__tooltip__item">
111
+ <div className="value-spec-paramater__tooltip__item__label">
112
+ Var Name
113
+ </div>
114
+ <div className="value-spec-paramater__tooltip__item__value">
115
+ {variable.name}
116
+ </div>
117
+ </div>
118
+ <div className="value-spec-paramater__tooltip__item">
119
+ <div className="value-spec-paramater__tooltip__item__label">
120
+ Multiplicity
121
+ </div>
122
+ <div className="value-spec-paramater__tooltip__item__value">
123
+ {getMultiplicityDescription(variable.multiplicity)}
124
+ </div>
125
+ </div>
126
+ </div>
127
+ }
128
+ >
129
+ {children}
130
+ </Tooltip>
131
+ );
132
+ };
133
+
134
+ const VariableExpressionParameterEditor = observer(
135
+ (props: {
136
+ valueSpecification: VariableExpression;
137
+ className?: string | undefined;
138
+ resetValue: () => void;
139
+ }) => {
140
+ const { valueSpecification, className, resetValue } = props;
141
+ const varName = valueSpecification.name;
142
+ return (
143
+ <div className={clsx('value-spec-editor__parameter', className)}>
144
+ <div className="value-spec-editor__parameter__icon">
145
+ <DollarIcon />
146
+ </div>
147
+ <div className="value-spec-editor__parameter__label">
148
+ <div className="value-spec-editor__parameter__text">{varName}</div>
149
+ <ParameterInfoTooltip variable={valueSpecification}>
150
+ <div className="value-spec-editor__parameter__info">
151
+ <InfoCircleIcon />
152
+ </div>
153
+ </ParameterInfoTooltip>
154
+ <button
155
+ className="value-spec-editor__parameter__reset-btn"
156
+ title="Reset"
157
+ onClick={resetValue}
158
+ >
159
+ <RefreshIcon />
160
+ </button>
161
+ </div>
162
+ </div>
163
+ );
164
+ },
165
+ );
166
+
167
+ const StringPrimitiveInstanceValueEditor = observer(
168
+ (props: {
169
+ valueSpecification: PrimitiveInstanceValue;
170
+ className?: string | undefined;
171
+ resetValue: () => void;
172
+ }) => {
173
+ const { valueSpecification, className, resetValue } = props;
174
+ const value = valueSpecification.values[0] as string;
175
+ const changeValue: React.ChangeEventHandler<HTMLInputElement> = (event) =>
176
+ instanceValue_changeValue(valueSpecification, event.target.value, 0);
177
+
178
+ return (
179
+ <div className={clsx('value-spec-editor', className)}>
180
+ <input
181
+ className="panel__content__form__section__input value-spec-editor__input"
182
+ spellCheck={false}
183
+ value={value}
184
+ placeholder={value === '' ? '(empty)' : undefined}
185
+ onChange={changeValue}
186
+ />
187
+ <button
188
+ className="value-spec-editor__reset-btn"
189
+ title="Reset"
190
+ onClick={resetValue}
191
+ >
192
+ <RefreshIcon />
193
+ </button>
194
+ </div>
195
+ );
196
+ },
197
+ );
198
+
199
+ const BooleanPrimitiveInstanceValueEditor = observer(
200
+ (props: {
201
+ valueSpecification: PrimitiveInstanceValue;
202
+ className?: string | undefined;
203
+ resetValue: () => void;
204
+ }) => {
205
+ const { valueSpecification, className, resetValue } = props;
206
+ const value = valueSpecification.values[0] as boolean;
207
+ const toggleValue = (): void =>
208
+ instanceValue_changeValue(valueSpecification, !value, 0);
209
+
210
+ return (
211
+ <div className={clsx('value-spec-editor', className)}>
212
+ <button
213
+ className={clsx('value-spec-editor__toggler__btn', {
214
+ 'value-spec-editor__toggler__btn--toggled': value,
215
+ })}
216
+ onClick={toggleValue}
217
+ >
218
+ {value ? <CheckSquareIcon /> : <SquareIcon />}
219
+ </button>
220
+ <button
221
+ className="value-spec-editor__reset-btn"
222
+ title="Reset"
223
+ onClick={resetValue}
224
+ >
225
+ <RefreshIcon />
226
+ </button>
227
+ </div>
228
+ );
229
+ },
230
+ );
231
+
232
+ const NumberPrimitiveInstanceValueEditor = observer(
233
+ (props: {
234
+ valueSpecification: PrimitiveInstanceValue;
235
+ isInteger: boolean;
236
+ className?: string | undefined;
237
+ resetValue: () => void;
238
+ }) => {
239
+ const { valueSpecification, isInteger, className, resetValue } = props;
240
+ const value = valueSpecification.values[0] as number;
241
+ const changeValue: React.ChangeEventHandler<HTMLInputElement> = (event) => {
242
+ let inputVal = isInteger
243
+ ? parseInt(event.target.value, 10)
244
+ : parseFloat(event.target.value);
245
+ inputVal = isNaN(inputVal) ? 0 : inputVal;
246
+ instanceValue_changeValue(valueSpecification, inputVal, 0);
247
+ };
248
+
249
+ return (
250
+ <div className={clsx('value-spec-editor', className)}>
251
+ <input
252
+ className="panel__content__form__section__input value-spec-editor__input"
253
+ spellCheck={false}
254
+ type="number"
255
+ value={value}
256
+ onChange={changeValue}
257
+ />
258
+ <button
259
+ className="value-spec-editor__reset-btn"
260
+ title="Reset"
261
+ onClick={resetValue}
262
+ >
263
+ <RefreshIcon />
264
+ </button>
265
+ </div>
266
+ );
267
+ },
268
+ );
269
+
270
+ const EnumValueInstanceValueEditor = observer(
271
+ (props: {
272
+ valueSpecification: EnumValueInstanceValue;
273
+ className?: string | undefined;
274
+ resetValue: () => void;
275
+ }) => {
276
+ const { valueSpecification, className, resetValue } = props;
277
+ const enumValueRef = guaranteeNonNullable(valueSpecification.values[0]);
278
+ const enumValue = enumValueRef.value;
279
+ const options = enumValue._OWNER.values.map((value) => ({
280
+ label: value.name,
281
+ value: value,
282
+ }));
283
+ const changeValue = (val: { value: Enum; label: string }): void => {
284
+ instanceValue_changeValue(
285
+ valueSpecification,
286
+ EnumValueExplicitReference.create(val.value),
287
+ 0,
288
+ );
289
+ };
290
+
291
+ return (
292
+ <div className={clsx('value-spec-editor', className)}>
293
+ <CustomSelectorInput
294
+ className="value-spec-editor__enum-selector"
295
+ options={options}
296
+ onChange={changeValue}
297
+ value={{ value: enumValue, label: enumValue.name }}
298
+ darkMode={true}
299
+ />
300
+ <button
301
+ className="value-spec-editor__reset-btn"
302
+ title="Reset"
303
+ onClick={resetValue}
304
+ >
305
+ <RefreshIcon />
306
+ </button>
307
+ </div>
308
+ );
309
+ },
310
+ );
311
+
312
+ const stringifyValue = (values: ValueSpecification[]): string => {
313
+ if (values.length === 0) {
314
+ return '';
315
+ }
316
+ return CSVParser.unparse([
317
+ values
318
+ .map((val) => {
319
+ if (val instanceof PrimitiveInstanceValue) {
320
+ return val.values[0];
321
+ } else if (val instanceof EnumValueInstanceValue) {
322
+ return guaranteeNonNullable(val.values[0]).value.name;
323
+ }
324
+ return undefined;
325
+ })
326
+ .filter(isNonNullable),
327
+ ]).trim();
328
+ };
329
+
330
+ /**
331
+ * NOTE: We attempt to be less disruptive here by not throwing errors left and right, instead
332
+ * we silently remove values which are not valid or parsable. But perhaps, we can consider
333
+ * passing in logger or notifier to show give the users some idea of what went wrong instead
334
+ * of silently swallow parts of their inputs like this.
335
+ */
336
+ const setCollectionValue = (
337
+ valueSpecification: CollectionInstanceValue,
338
+ graph: PureModel,
339
+ expectedType: Type,
340
+ value: string,
341
+ ): void => {
342
+ if (value.trim().length === 0) {
343
+ instanceValue_changeValues(valueSpecification, []);
344
+ return;
345
+ }
346
+ const multiplicityOne = graph.getTypicalMultiplicity(
347
+ TYPICAL_MULTIPLICITY_TYPE.ONE,
348
+ );
349
+ let result: unknown[] = [];
350
+ const parseResult = CSVParser.parse<string[]>(value.trim(), {
351
+ delimiter: ',',
352
+ });
353
+ const parseData = parseResult.data[0] as string[]; // only take the first line
354
+ if (parseResult.errors.length) {
355
+ if (
356
+ parseResult.errors[0] &&
357
+ parseResult.errors[0].code === 'UndetectableDelimiter' &&
358
+ parseResult.errors[0].type === 'Delimiter' &&
359
+ parseResult.data.length === 1
360
+ ) {
361
+ // NOTE: this happens when the user only put one item in the value input
362
+ // we can go the other way by ensure the input has a comma but this is arguably neater
363
+ // as it tinkers with the parser
364
+ } else {
365
+ // there were some parsing error, escape
366
+ // NOTE: ideally, we could show a warning here
367
+ return;
368
+ }
369
+ } else if (expectedType instanceof PrimitiveType) {
370
+ switch (expectedType.path) {
371
+ case PRIMITIVE_TYPE.STRING: {
372
+ result = uniq(parseData)
373
+ .map((item): PrimitiveInstanceValue | undefined => {
374
+ const primitiveInstanceValue = new PrimitiveInstanceValue(
375
+ GenericTypeExplicitReference.create(
376
+ new GenericType(expectedType),
377
+ ),
378
+ multiplicityOne,
379
+ );
380
+ primitiveInstanceValue.values = [item.toString()];
381
+ return primitiveInstanceValue;
382
+ })
383
+ .filter(isNonNullable);
384
+ break;
385
+ }
386
+ case PRIMITIVE_TYPE.NUMBER:
387
+ case PRIMITIVE_TYPE.FLOAT:
388
+ case PRIMITIVE_TYPE.DECIMAL:
389
+ case PRIMITIVE_TYPE.INTEGER: {
390
+ result = uniq(
391
+ parseData
392
+ .filter((val) => !isNaN(Number(val)))
393
+ .map((val) => Number(val)),
394
+ )
395
+ .map((item): PrimitiveInstanceValue | undefined => {
396
+ const primitiveInstanceValue = new PrimitiveInstanceValue(
397
+ GenericTypeExplicitReference.create(
398
+ new GenericType(expectedType),
399
+ ),
400
+ multiplicityOne,
401
+ );
402
+ primitiveInstanceValue.values = [item];
403
+ return primitiveInstanceValue;
404
+ })
405
+ .filter(isNonNullable);
406
+ break;
407
+ }
408
+ default:
409
+ // unsupported expected type, just escape
410
+ return;
411
+ }
412
+ } else if (expectedType instanceof Enumeration) {
413
+ result = uniq(parseData.map((item) => item.trim()))
414
+ .map((item): EnumValueInstanceValue | undefined => {
415
+ const _enum = returnUndefOnError(() =>
416
+ getEnumValue(expectedType, item),
417
+ );
418
+ if (!_enum) {
419
+ return undefined;
420
+ }
421
+ const enumValueInstanceValue = new EnumValueInstanceValue(
422
+ GenericTypeExplicitReference.create(new GenericType(expectedType)),
423
+ multiplicityOne,
424
+ );
425
+ enumValueInstanceValue.values = [
426
+ EnumValueExplicitReference.create(_enum),
427
+ ];
428
+ return enumValueInstanceValue;
429
+ })
430
+ .filter(isNonNullable);
431
+ }
432
+ instanceValue_changeValues(valueSpecification, result);
433
+ };
434
+
435
+ const COLLECTION_PREVIEW_CHAR_LIMIT = 50;
436
+
437
+ const CollectionValueInstanceValueEditor = observer(
438
+ (props: {
439
+ valueSpecification: CollectionInstanceValue;
440
+ graph: PureModel;
441
+ expectedType: Type;
442
+ className?: string | undefined;
443
+ resetValue: () => void;
444
+ }) => {
445
+ const { valueSpecification, graph, expectedType, className, resetValue } =
446
+ props;
447
+ const inputRef = useRef<HTMLInputElement>(null);
448
+ const [text, setText] = useState(stringifyValue(valueSpecification.values));
449
+ const [editable, setEditable] = useState(false);
450
+ const valueText = stringifyValue(valueSpecification.values);
451
+ const previewText = `List(${
452
+ valueSpecification.values.length === 0
453
+ ? 'empty'
454
+ : valueSpecification.values.length
455
+ })${
456
+ valueSpecification.values.length === 0
457
+ ? ''
458
+ : `: ${
459
+ valueText.length > COLLECTION_PREVIEW_CHAR_LIMIT
460
+ ? `${valueText.substring(0, COLLECTION_PREVIEW_CHAR_LIMIT)}...`
461
+ : valueText
462
+ }`
463
+ }`;
464
+ const enableEdit = (): void => setEditable(true);
465
+ const saveEdit = (): void => {
466
+ setEditable(false);
467
+ setCollectionValue(valueSpecification, graph, expectedType, text);
468
+ setText(stringifyValue(valueSpecification.values));
469
+ };
470
+ const changeValue: React.ChangeEventHandler<HTMLInputElement> = (event) =>
471
+ setText(event.target.value);
472
+
473
+ // focus the input box when edit is enabled
474
+ useEffect(() => {
475
+ if (editable) {
476
+ inputRef.current?.focus();
477
+ }
478
+ }, [editable]);
479
+
480
+ if (editable) {
481
+ return (
482
+ <div className={clsx('value-spec-editor', className)}>
483
+ <input
484
+ ref={inputRef}
485
+ className="panel__content__form__section__input value-spec-editor__input"
486
+ spellCheck={false}
487
+ value={text}
488
+ placeholder={text === '' ? '(empty)' : undefined}
489
+ onChange={changeValue}
490
+ />
491
+ <button
492
+ className="value-spec-editor__list-editor__save-button btn--dark"
493
+ onClick={saveEdit}
494
+ >
495
+ <SaveIcon />
496
+ </button>
497
+ <button
498
+ className="value-spec-editor__reset-btn"
499
+ title="Reset"
500
+ onClick={resetValue}
501
+ >
502
+ <RefreshIcon />
503
+ </button>
504
+ </div>
505
+ );
506
+ }
507
+ return (
508
+ <div
509
+ className={clsx('value-spec-editor', className)}
510
+ onClick={enableEdit}
511
+ title="Click to edit"
512
+ >
513
+ <input
514
+ className="value-spec-editor__list-editor__preview"
515
+ spellCheck={false}
516
+ value={previewText}
517
+ disabled={true}
518
+ />
519
+ <button className="value-spec-editor__list-editor__edit-icon">
520
+ <PencilIcon />
521
+ </button>
522
+ </div>
523
+ );
524
+ },
525
+ );
526
+
527
+ const UnsupportedValueSpecificationEditor: React.FC = () => (
528
+ <div className="value-spec-editor--unsupported">unsupported</div>
529
+ );
530
+
531
+ const DateInstanceValueEditor = observer(
532
+ (props: {
533
+ valueSpecification: PrimitiveInstanceValue | SimpleFunctionExpression;
534
+ graph: PureModel;
535
+ typeCheckOption: TypeCheckOption;
536
+ className?: string | undefined;
537
+ updateValue: (val: ValueSpecification) => void;
538
+ resetValue: () => void;
539
+ }) => {
540
+ const {
541
+ valueSpecification,
542
+ updateValue,
543
+ graph,
544
+ typeCheckOption,
545
+ resetValue,
546
+ } = props;
547
+
548
+ return (
549
+ <div className="value-spec-editor">
550
+ <CustomDatePicker
551
+ valueSpecification={valueSpecification}
552
+ graph={graph}
553
+ typeCheckOption={typeCheckOption}
554
+ updateValue={updateValue}
555
+ />
556
+ <button
557
+ className="value-spec-editor__reset-btn"
558
+ title="Reset"
559
+ onClick={resetValue}
560
+ >
561
+ <RefreshIcon />
562
+ </button>
563
+ </div>
564
+ );
565
+ },
566
+ );
567
+
568
+ /**
569
+ * TODO we should pass in the props `setValueSpecification` and `resetValueSpecification`. Reset
570
+ * should be part of this editor. Also through here we can call `observe_` accordingly.
571
+ *
572
+ * See https://github.com/finos/legend-studio/pull/1021
573
+ */
574
+ export const BasicValueSpecificationEditor: React.FC<{
575
+ valueSpecification: ValueSpecification;
576
+ graph: PureModel;
577
+ typeCheckOption: TypeCheckOption;
578
+ className?: string | undefined;
579
+ updateValue: (val: ValueSpecification) => void;
580
+ resetValue: () => void;
581
+ }> = (props) => {
582
+ const {
583
+ className,
584
+ valueSpecification,
585
+ graph,
586
+ typeCheckOption,
587
+ updateValue,
588
+ resetValue,
589
+ } = props;
590
+ if (valueSpecification instanceof PrimitiveInstanceValue) {
591
+ const _type = valueSpecification.genericType.value.rawType;
592
+ switch (_type.path) {
593
+ case PRIMITIVE_TYPE.STRING:
594
+ return (
595
+ <StringPrimitiveInstanceValueEditor
596
+ valueSpecification={valueSpecification}
597
+ className={className}
598
+ resetValue={resetValue}
599
+ />
600
+ );
601
+ case PRIMITIVE_TYPE.BOOLEAN:
602
+ return (
603
+ <BooleanPrimitiveInstanceValueEditor
604
+ valueSpecification={valueSpecification}
605
+ className={className}
606
+ resetValue={resetValue}
607
+ />
608
+ );
609
+ case PRIMITIVE_TYPE.NUMBER:
610
+ case PRIMITIVE_TYPE.FLOAT:
611
+ case PRIMITIVE_TYPE.DECIMAL:
612
+ case PRIMITIVE_TYPE.INTEGER:
613
+ return (
614
+ <NumberPrimitiveInstanceValueEditor
615
+ valueSpecification={valueSpecification}
616
+ isInteger={_type.path === PRIMITIVE_TYPE.INTEGER}
617
+ className={className}
618
+ resetValue={resetValue}
619
+ />
620
+ );
621
+ case PRIMITIVE_TYPE.DATE:
622
+ case PRIMITIVE_TYPE.STRICTDATE:
623
+ case PRIMITIVE_TYPE.DATETIME:
624
+ case PRIMITIVE_TYPE.LATESTDATE:
625
+ return (
626
+ <DateInstanceValueEditor
627
+ valueSpecification={valueSpecification}
628
+ graph={graph}
629
+ typeCheckOption={typeCheckOption}
630
+ className={className}
631
+ updateValue={updateValue}
632
+ resetValue={resetValue}
633
+ />
634
+ );
635
+ default:
636
+ return <UnsupportedValueSpecificationEditor />;
637
+ }
638
+ } else if (valueSpecification instanceof EnumValueInstanceValue) {
639
+ return (
640
+ <EnumValueInstanceValueEditor
641
+ valueSpecification={valueSpecification}
642
+ className={className}
643
+ resetValue={resetValue}
644
+ />
645
+ );
646
+ } else if (
647
+ valueSpecification instanceof CollectionInstanceValue &&
648
+ valueSpecification.genericType
649
+ ) {
650
+ // NOTE: since when we fill in the arguments, `[]` (or `nullish` value in Pure)
651
+ // is used for parameters we don't handle, we should not attempt to support empty collection
652
+ // without generic type here as that is equivalent to `[]`
653
+ return (
654
+ <CollectionValueInstanceValueEditor
655
+ valueSpecification={valueSpecification}
656
+ graph={graph}
657
+ expectedType={typeCheckOption.expectedType}
658
+ className={className}
659
+ resetValue={resetValue}
660
+ />
661
+ );
662
+ }
663
+ // property expression
664
+ else if (valueSpecification instanceof VariableExpression) {
665
+ return (
666
+ <VariableExpressionParameterEditor
667
+ valueSpecification={valueSpecification}
668
+ className={className}
669
+ resetValue={resetValue}
670
+ />
671
+ );
672
+ } else if (valueSpecification instanceof INTERNAL__PropagatedValue) {
673
+ return (
674
+ <BasicValueSpecificationEditor
675
+ valueSpecification={valueSpecification.getValue()}
676
+ graph={graph}
677
+ typeCheckOption={typeCheckOption}
678
+ updateValue={updateValue}
679
+ resetValue={resetValue}
680
+ />
681
+ );
682
+ } else if (
683
+ valueSpecification instanceof SimpleFunctionExpression &&
684
+ [
685
+ PRIMITIVE_TYPE.DATE.toString(),
686
+ PRIMITIVE_TYPE.STRICTDATE.toString(),
687
+ PRIMITIVE_TYPE.DATETIME.toString(),
688
+ PRIMITIVE_TYPE.LATESTDATE.toString(),
689
+ ].includes(typeCheckOption.expectedType.path)
690
+ ) {
691
+ return (
692
+ <DateInstanceValueEditor
693
+ valueSpecification={valueSpecification}
694
+ graph={graph}
695
+ typeCheckOption={typeCheckOption}
696
+ className={className}
697
+ updateValue={updateValue}
698
+ resetValue={resetValue}
699
+ />
700
+ );
701
+ }
702
+ return <UnsupportedValueSpecificationEditor />;
703
+ };
@@ -17,7 +17,7 @@
17
17
  import { observer } from 'mobx-react-lite';
18
18
  import { PanelLoadingIndicator, Dialog } from '@finos/legend-art';
19
19
  import { noop } from '@finos/legend-shared';
20
- import { useApplicationStore } from './ApplicationStoreProvider';
20
+ import { useApplicationStore } from './ApplicationStoreProvider.js';
21
21
 
22
22
  /**
23
23
  * The users of this need to justify their use case because blocking app disrupts the UX flow.