@finos/legend-application 7.0.3 → 7.1.1
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/lib/components/shared/BasicValueSpecificationEditor.d.ts +8 -0
- package/lib/components/shared/BasicValueSpecificationEditor.d.ts.map +1 -1
- package/lib/components/shared/BasicValueSpecificationEditor.js +44 -6
- package/lib/components/shared/BasicValueSpecificationEditor.js.map +1 -1
- package/lib/components/shared/LambdaEditor.d.ts +1 -0
- package/lib/components/shared/LambdaEditor.d.ts.map +1 -1
- package/lib/components/shared/LambdaEditor.js +12 -5
- package/lib/components/shared/LambdaEditor.js.map +1 -1
- package/lib/components/shared/LambdaParameterValuesEditor.d.ts.map +1 -1
- package/lib/components/shared/LambdaParameterValuesEditor.js +2 -2
- package/lib/components/shared/LambdaParameterValuesEditor.js.map +1 -1
- package/lib/components/shared/PackageableElementOptionRenderer.d.ts +2 -2
- package/lib/components/shared/PackageableElementOptionRenderer.d.ts.map +1 -1
- package/lib/components/shared/PackageableElementOptionRenderer.js +36 -3
- package/lib/components/shared/PackageableElementOptionRenderer.js.map +1 -1
- package/lib/components/shared/TextInputEditor.d.ts.map +1 -1
- package/lib/components/shared/TextInputEditor.js +3 -1
- package/lib/components/shared/TextInputEditor.js.map +1 -1
- package/lib/const.d.ts +2 -1
- package/lib/const.d.ts.map +1 -1
- package/lib/const.js +1 -0
- package/lib/const.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/stores/ApplicationStore.d.ts +7 -0
- package/lib/stores/ApplicationStore.d.ts.map +1 -1
- package/lib/stores/ApplicationStore.js +11 -0
- package/lib/stores/ApplicationStore.js.map +1 -1
- package/lib/stores/LegendApplicationSDLCSetupState.d.ts +30 -0
- package/lib/stores/LegendApplicationSDLCSetupState.d.ts.map +1 -0
- package/lib/stores/LegendApplicationSDLCSetupState.js +128 -0
- package/lib/stores/LegendApplicationSDLCSetupState.js.map +1 -0
- package/package.json +11 -10
- package/src/components/shared/BasicValueSpecificationEditor.tsx +105 -11
- package/src/components/shared/LambdaEditor.tsx +19 -2
- package/src/components/shared/LambdaParameterValuesEditor.tsx +7 -5
- package/src/components/shared/PackageableElementOptionRenderer.tsx +37 -3
- package/src/components/shared/TextInputEditor.tsx +3 -1
- package/src/const.ts +1 -0
- package/src/index.ts +1 -0
- package/src/stores/ApplicationStore.ts +13 -0
- package/src/stores/LegendApplicationSDLCSetupState.ts +175 -0
- package/tsconfig.json +1 -0
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
18
|
type TooltipPlacement,
|
|
19
|
+
type InputActionMeta,
|
|
19
20
|
Tooltip,
|
|
20
21
|
DollarIcon,
|
|
21
22
|
clsx,
|
|
@@ -49,11 +50,14 @@ import {
|
|
|
49
50
|
getMultiplicityDescription,
|
|
50
51
|
} from '@finos/legend-graph';
|
|
51
52
|
import {
|
|
53
|
+
type DebouncedFunc,
|
|
54
|
+
type GeneratorFn,
|
|
52
55
|
guaranteeNonNullable,
|
|
53
56
|
isNonNullable,
|
|
54
57
|
returnUndefOnError,
|
|
55
58
|
uniq,
|
|
56
59
|
} from '@finos/legend-shared';
|
|
60
|
+
import { flowResult } from 'mobx';
|
|
57
61
|
import { observer } from 'mobx-react-lite';
|
|
58
62
|
import CSVParser from 'papaparse';
|
|
59
63
|
import { useEffect, useRef, useState } from 'react';
|
|
@@ -61,6 +65,7 @@ import {
|
|
|
61
65
|
instanceValue_changeValue,
|
|
62
66
|
instanceValue_changeValues,
|
|
63
67
|
} from '../../stores/shared/ValueSpecificationModifierHelper.js';
|
|
68
|
+
import { useApplicationStore } from '../ApplicationStoreProvider.js';
|
|
64
69
|
import { CustomDatePicker } from './CustomDatePicker.js';
|
|
65
70
|
|
|
66
71
|
type TypeCheckOption = {
|
|
@@ -170,23 +175,100 @@ const StringPrimitiveInstanceValueEditor = observer(
|
|
|
170
175
|
className?: string | undefined;
|
|
171
176
|
setValueSpecification: (val: ValueSpecification) => void;
|
|
172
177
|
resetValue: () => void;
|
|
178
|
+
selectorConfig?:
|
|
179
|
+
| {
|
|
180
|
+
values: string[] | undefined;
|
|
181
|
+
isLoading: boolean;
|
|
182
|
+
reloadValues:
|
|
183
|
+
| DebouncedFunc<(inputValue: string) => GeneratorFn<void>>
|
|
184
|
+
| undefined;
|
|
185
|
+
cleanUpReloadValues?: () => void;
|
|
186
|
+
}
|
|
187
|
+
| undefined;
|
|
173
188
|
}) => {
|
|
174
|
-
const {
|
|
175
|
-
|
|
189
|
+
const {
|
|
190
|
+
valueSpecification,
|
|
191
|
+
className,
|
|
192
|
+
resetValue,
|
|
193
|
+
setValueSpecification,
|
|
194
|
+
selectorConfig,
|
|
195
|
+
} = props;
|
|
196
|
+
const useSelector = Boolean(selectorConfig);
|
|
197
|
+
const applicationStore = useApplicationStore();
|
|
176
198
|
const value = valueSpecification.values[0] as string;
|
|
177
|
-
const
|
|
178
|
-
instanceValue_changeValue(valueSpecification,
|
|
199
|
+
const updateValueSpec = (val: string): void => {
|
|
200
|
+
instanceValue_changeValue(valueSpecification, val, 0);
|
|
179
201
|
setValueSpecification(valueSpecification);
|
|
180
202
|
};
|
|
203
|
+
const changeInputValue: React.ChangeEventHandler<HTMLInputElement> = (
|
|
204
|
+
event,
|
|
205
|
+
) => {
|
|
206
|
+
updateValueSpec(event.target.value);
|
|
207
|
+
};
|
|
208
|
+
// custom select
|
|
209
|
+
const selectedValue = { value: value, label: value };
|
|
210
|
+
const reloadValuesFunc = selectorConfig?.reloadValues;
|
|
211
|
+
const changeValue = (
|
|
212
|
+
val: null | { value: number | string; label: string },
|
|
213
|
+
): void => {
|
|
214
|
+
const newValue = val === null ? '' : val.value.toString();
|
|
215
|
+
updateValueSpec(newValue);
|
|
216
|
+
};
|
|
217
|
+
const handleInputChange = (
|
|
218
|
+
inputValue: string,
|
|
219
|
+
actionChange: InputActionMeta,
|
|
220
|
+
): void => {
|
|
221
|
+
if (actionChange.action === 'input-change') {
|
|
222
|
+
updateValueSpec(inputValue);
|
|
223
|
+
reloadValuesFunc?.cancel();
|
|
224
|
+
const reloadValuesFuncTransformation = reloadValuesFunc?.(inputValue);
|
|
225
|
+
if (reloadValuesFuncTransformation) {
|
|
226
|
+
flowResult(reloadValuesFuncTransformation).catch(
|
|
227
|
+
applicationStore.alertUnhandledError,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (actionChange.action === 'input-blur') {
|
|
232
|
+
reloadValuesFunc?.cancel();
|
|
233
|
+
selectorConfig?.cleanUpReloadValues?.();
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
const isLoading = selectorConfig?.isLoading;
|
|
237
|
+
const queryOptions = selectorConfig?.values?.length
|
|
238
|
+
? selectorConfig.values.map((e) => ({
|
|
239
|
+
value: e,
|
|
240
|
+
label: e.toString(),
|
|
241
|
+
}))
|
|
242
|
+
: undefined;
|
|
243
|
+
const noOptionsMessage =
|
|
244
|
+
selectorConfig?.values === undefined ? (): null => null : undefined;
|
|
245
|
+
|
|
181
246
|
return (
|
|
182
247
|
<div className={clsx('value-spec-editor', className)}>
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
248
|
+
{useSelector ? (
|
|
249
|
+
<CustomSelectorInput
|
|
250
|
+
className="value-spec-editor__enum-selector"
|
|
251
|
+
options={queryOptions}
|
|
252
|
+
onChange={changeValue}
|
|
253
|
+
value={selectedValue}
|
|
254
|
+
onInputChange={handleInputChange}
|
|
255
|
+
darkMode={!applicationStore.TEMPORARY__isLightThemeEnabled}
|
|
256
|
+
isLoading={isLoading}
|
|
257
|
+
allowCreateWhileLoading={true}
|
|
258
|
+
noOptionsMessage={noOptionsMessage}
|
|
259
|
+
components={{
|
|
260
|
+
DropdownIndicator: null,
|
|
261
|
+
}}
|
|
262
|
+
/>
|
|
263
|
+
) : (
|
|
264
|
+
<input
|
|
265
|
+
className="panel__content__form__section__input value-spec-editor__input"
|
|
266
|
+
spellCheck={false}
|
|
267
|
+
value={value}
|
|
268
|
+
placeholder={value === '' ? '(empty)' : undefined}
|
|
269
|
+
onChange={changeInputValue}
|
|
270
|
+
/>
|
|
271
|
+
)}
|
|
190
272
|
<button
|
|
191
273
|
className="value-spec-editor__reset-btn"
|
|
192
274
|
title="Reset"
|
|
@@ -604,6 +686,16 @@ export const BasicValueSpecificationEditor: React.FC<{
|
|
|
604
686
|
className?: string | undefined;
|
|
605
687
|
setValueSpecification: (val: ValueSpecification) => void;
|
|
606
688
|
resetValue: () => void;
|
|
689
|
+
selectorConfig?:
|
|
690
|
+
| {
|
|
691
|
+
values: string[] | undefined;
|
|
692
|
+
isLoading: boolean;
|
|
693
|
+
reloadValues:
|
|
694
|
+
| DebouncedFunc<(inputValue: string) => GeneratorFn<void>>
|
|
695
|
+
| undefined;
|
|
696
|
+
cleanUpReloadValues?: () => void;
|
|
697
|
+
}
|
|
698
|
+
| undefined;
|
|
607
699
|
}> = (props) => {
|
|
608
700
|
const {
|
|
609
701
|
className,
|
|
@@ -612,6 +704,7 @@ export const BasicValueSpecificationEditor: React.FC<{
|
|
|
612
704
|
typeCheckOption,
|
|
613
705
|
setValueSpecification,
|
|
614
706
|
resetValue,
|
|
707
|
+
selectorConfig,
|
|
615
708
|
} = props;
|
|
616
709
|
if (valueSpecification instanceof PrimitiveInstanceValue) {
|
|
617
710
|
const _type = valueSpecification.genericType.value.rawType;
|
|
@@ -623,6 +716,7 @@ export const BasicValueSpecificationEditor: React.FC<{
|
|
|
623
716
|
setValueSpecification={setValueSpecification}
|
|
624
717
|
className={className}
|
|
625
718
|
resetValue={resetValue}
|
|
719
|
+
selectorConfig={selectorConfig}
|
|
626
720
|
/>
|
|
627
721
|
);
|
|
628
722
|
case PRIMITIVE_TYPE.BOOLEAN:
|
|
@@ -100,6 +100,7 @@ const LambdaEditorInline = observer(
|
|
|
100
100
|
backdropSetter?: ((val: boolean) => void) | undefined;
|
|
101
101
|
onKeyDownEventHandlers: LambdaEditorOnKeyDownEventHandler[];
|
|
102
102
|
openInPopUp: () => void;
|
|
103
|
+
onEditorFocusEventHandler?: (() => void) | undefined;
|
|
103
104
|
}) => {
|
|
104
105
|
const {
|
|
105
106
|
className,
|
|
@@ -118,12 +119,16 @@ const LambdaEditorInline = observer(
|
|
|
118
119
|
hideErrorBar,
|
|
119
120
|
onKeyDownEventHandlers,
|
|
120
121
|
openInPopUp,
|
|
122
|
+
onEditorFocusEventHandler,
|
|
121
123
|
} = props;
|
|
122
124
|
const applicationStore = useApplicationStore();
|
|
123
125
|
const onDidChangeModelContentEventDisposer = useRef<
|
|
124
126
|
IDisposable | undefined
|
|
125
127
|
>(undefined);
|
|
126
128
|
const onKeyDownEventDisposer = useRef<IDisposable | undefined>(undefined);
|
|
129
|
+
const onDidFocusEditorWidgetDisposer = useRef<IDisposable | undefined>(
|
|
130
|
+
undefined,
|
|
131
|
+
);
|
|
127
132
|
const value = normalizeLineEnding(lambdaEditorState.lambdaString);
|
|
128
133
|
const parserError = lambdaEditorState.parserError;
|
|
129
134
|
const compilationError = lambdaEditorState.compilationError;
|
|
@@ -183,13 +188,15 @@ const LambdaEditorInline = observer(
|
|
|
183
188
|
const _editor = monacoEditorAPI.create(element, {
|
|
184
189
|
...baseTextEditorSettings,
|
|
185
190
|
language: EDITOR_LANGUAGE.PURE,
|
|
186
|
-
theme:
|
|
191
|
+
theme: applicationStore.TEMPORARY__isLightThemeEnabled
|
|
192
|
+
? EDITOR_THEME.TEMPORARY__VSCODE_LIGHT
|
|
193
|
+
: EDITOR_THEME.LEGEND,
|
|
187
194
|
...lambdaEditorOptions,
|
|
188
195
|
});
|
|
189
196
|
disableEditorHotKeys(_editor);
|
|
190
197
|
setEditor(_editor);
|
|
191
198
|
}
|
|
192
|
-
}, [editor, useBaseTextEditorSettings]);
|
|
199
|
+
}, [editor, applicationStore, useBaseTextEditorSettings]);
|
|
193
200
|
|
|
194
201
|
// set styling for expanded mode
|
|
195
202
|
useEffect(() => {
|
|
@@ -305,6 +312,13 @@ const LambdaEditorInline = observer(
|
|
|
305
312
|
});
|
|
306
313
|
});
|
|
307
314
|
|
|
315
|
+
onDidFocusEditorWidgetDisposer.current?.dispose();
|
|
316
|
+
onDidFocusEditorWidgetDisposer.current = editor.onDidFocusEditorWidget(
|
|
317
|
+
() => {
|
|
318
|
+
onEditorFocusEventHandler?.();
|
|
319
|
+
},
|
|
320
|
+
);
|
|
321
|
+
|
|
308
322
|
// Set the text value
|
|
309
323
|
const currentValue = getEditorValue(editor);
|
|
310
324
|
const editorModel = editor.getModel();
|
|
@@ -738,6 +752,7 @@ export const LambdaEditor = observer(
|
|
|
738
752
|
* to allow activating global hotkeys while typing in the editor
|
|
739
753
|
*/
|
|
740
754
|
onKeyDownEventHandlers?: LambdaEditorOnKeyDownEventHandler[];
|
|
755
|
+
onEditorFocusEventHandler?: (() => void) | undefined;
|
|
741
756
|
}) => {
|
|
742
757
|
const {
|
|
743
758
|
className,
|
|
@@ -754,6 +769,7 @@ export const LambdaEditor = observer(
|
|
|
754
769
|
useBaseTextEditorSettings,
|
|
755
770
|
hideErrorBar,
|
|
756
771
|
onKeyDownEventHandlers,
|
|
772
|
+
onEditorFocusEventHandler,
|
|
757
773
|
} = props;
|
|
758
774
|
const [showPopUp, setShowPopUp] = useState(false);
|
|
759
775
|
const openInPopUp = (): void => setShowPopUp(true);
|
|
@@ -831,6 +847,7 @@ export const LambdaEditor = observer(
|
|
|
831
847
|
hideErrorBar={hideErrorBar}
|
|
832
848
|
onKeyDownEventHandlers={onKeyDownEventHandlers ?? []}
|
|
833
849
|
openInPopUp={openInPopUp}
|
|
850
|
+
onEditorFocusEventHandler={onEditorFocusEventHandler}
|
|
834
851
|
/>
|
|
835
852
|
);
|
|
836
853
|
},
|
|
@@ -53,11 +53,11 @@ export const LambdaParameterValuesEditor = observer(
|
|
|
53
53
|
paper: 'editor-modal__content',
|
|
54
54
|
}}
|
|
55
55
|
>
|
|
56
|
-
<div className="modal modal--dark editor-modal
|
|
56
|
+
<div className="modal modal--dark editor-modal lambda-parameter-values__modal">
|
|
57
57
|
<div className="modal__header">
|
|
58
58
|
<div className="modal__title">Set Parameter Values</div>
|
|
59
59
|
</div>
|
|
60
|
-
<div className="modal__body
|
|
60
|
+
<div className="modal__body lambda-parameter-values__modal__body">
|
|
61
61
|
{lambdaParametersState.parameterStates.map((paramState) => {
|
|
62
62
|
const stringType = graph.getPrimitiveType(PRIMITIVE_TYPE.STRING);
|
|
63
63
|
const variableType = paramState.variableType ?? stringType;
|
|
@@ -66,9 +66,11 @@ export const LambdaParameterValuesEditor = observer(
|
|
|
66
66
|
key={paramState.uuid}
|
|
67
67
|
className="panel__content__form__section"
|
|
68
68
|
>
|
|
69
|
-
<div className="
|
|
70
|
-
<div
|
|
71
|
-
|
|
69
|
+
<div className="lambda-parameter-values__value__label">
|
|
70
|
+
<div className="lambda-parameter-values__value__label__name">
|
|
71
|
+
{paramState.parameter.name}
|
|
72
|
+
</div>
|
|
73
|
+
<div className="lambda-parameter-values__value__label__type">
|
|
72
74
|
{variableType.name}
|
|
73
75
|
</div>
|
|
74
76
|
</div>
|
|
@@ -14,10 +14,35 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import
|
|
17
|
+
import {
|
|
18
|
+
type PackageableElement,
|
|
19
|
+
isSystemElement,
|
|
20
|
+
isGeneratedElement,
|
|
21
|
+
isDependencyElement,
|
|
22
|
+
} from '@finos/legend-graph';
|
|
18
23
|
import type { PackageableElementOption } from '../../stores/shared/PackageableElementOption.js';
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
const getElementColorCode = (element: PackageableElement): string =>
|
|
26
|
+
isSystemElement(element)
|
|
27
|
+
? 'system'
|
|
28
|
+
: isGeneratedElement(element)
|
|
29
|
+
? 'generated'
|
|
30
|
+
: isDependencyElement(element)
|
|
31
|
+
? 'dependency'
|
|
32
|
+
: '';
|
|
33
|
+
|
|
34
|
+
const generateOptionTooltipText = (
|
|
35
|
+
element: PackageableElement,
|
|
36
|
+
): string | undefined =>
|
|
37
|
+
isSystemElement(element)
|
|
38
|
+
? 'system element'
|
|
39
|
+
: isGeneratedElement(element)
|
|
40
|
+
? 'generated element'
|
|
41
|
+
: isDependencyElement(element)
|
|
42
|
+
? 'dependency element'
|
|
43
|
+
: undefined;
|
|
44
|
+
|
|
45
|
+
export const getPackageableElementOptionFormatter = (props: {
|
|
21
46
|
darkMode?: boolean;
|
|
22
47
|
}): ((
|
|
23
48
|
option: PackageableElementOption<PackageableElement>,
|
|
@@ -25,12 +50,21 @@ export const getPackageableElementOptionalFormatter = (props?: {
|
|
|
25
50
|
function PackageableElementOptionLabel(
|
|
26
51
|
option: PackageableElementOption<PackageableElement>,
|
|
27
52
|
): React.ReactNode {
|
|
28
|
-
const className = props
|
|
53
|
+
const className = props.darkMode
|
|
29
54
|
? 'packageable-element-format-option-label--dark'
|
|
30
55
|
: 'packageable-element-format-option-label';
|
|
56
|
+
const colorCode = getElementColorCode(option.value);
|
|
31
57
|
|
|
32
58
|
return (
|
|
33
59
|
<div className={className}>
|
|
60
|
+
<div
|
|
61
|
+
title={generateOptionTooltipText(option.value)}
|
|
62
|
+
className={`packageable-element-format-option-label-type ${
|
|
63
|
+
colorCode
|
|
64
|
+
? `packageable-element-format-option-label-type--${colorCode}`
|
|
65
|
+
: ''
|
|
66
|
+
} `}
|
|
67
|
+
></div>
|
|
34
68
|
<div className={`${className}__name`}>{option.label}</div>
|
|
35
69
|
{option.value.package && (
|
|
36
70
|
<div className={`${className}__tag`}>{option.value.path}</div>
|
|
@@ -92,7 +92,9 @@ export const TextInputEditor: React.FC<{
|
|
|
92
92
|
const element = textInputRef.current;
|
|
93
93
|
const _editor = monacoEditorAPI.create(element, {
|
|
94
94
|
...baseTextEditorSettings,
|
|
95
|
-
theme:
|
|
95
|
+
theme: applicationStore.TEMPORARY__isLightThemeEnabled
|
|
96
|
+
? EDITOR_THEME.TEMPORARY__VSCODE_LIGHT
|
|
97
|
+
: EDITOR_THEME.LEGEND,
|
|
96
98
|
formatOnType: true,
|
|
97
99
|
formatOnPaste: true,
|
|
98
100
|
});
|
package/src/const.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -40,6 +40,7 @@ export * from './stores/ApplicationNavigationContextService.js';
|
|
|
40
40
|
export * from './stores/LegendApplicationPlugin.js';
|
|
41
41
|
|
|
42
42
|
export * from './stores/ApplicationStoreTestUtils.js';
|
|
43
|
+
export * from './stores/LegendApplicationSDLCSetupState.js';
|
|
43
44
|
|
|
44
45
|
// ------------------------------------------- Shared components -------------------------------------------
|
|
45
46
|
|
|
@@ -136,6 +136,14 @@ export class ApplicationStore<
|
|
|
136
136
|
telemetryService = new TelemetryService();
|
|
137
137
|
tracerService = new TracerService();
|
|
138
138
|
|
|
139
|
+
// theme
|
|
140
|
+
/**
|
|
141
|
+
* NOTE: this is the poor man way of doing theming
|
|
142
|
+
* we would need to revise this flag later
|
|
143
|
+
* See https://github.com/finos/legend-studio/issues/264
|
|
144
|
+
*/
|
|
145
|
+
TEMPORARY__isLightThemeEnabled = false;
|
|
146
|
+
|
|
139
147
|
constructor(
|
|
140
148
|
config: T,
|
|
141
149
|
navigator: WebApplicationNavigator,
|
|
@@ -151,6 +159,7 @@ export class ApplicationStore<
|
|
|
151
159
|
notifyWarning: action,
|
|
152
160
|
notifyIllegalState: action,
|
|
153
161
|
notifyError: action,
|
|
162
|
+
TEMPORARY__setIsLightThemeEnabled: action,
|
|
154
163
|
});
|
|
155
164
|
|
|
156
165
|
this.config = config;
|
|
@@ -173,6 +182,10 @@ export class ApplicationStore<
|
|
|
173
182
|
);
|
|
174
183
|
}
|
|
175
184
|
|
|
185
|
+
TEMPORARY__setIsLightThemeEnabled(val: boolean): void {
|
|
186
|
+
this.TEMPORARY__isLightThemeEnabled = val;
|
|
187
|
+
}
|
|
188
|
+
|
|
176
189
|
setBlockingAlert(alertInfo: BlockingAlertInfo | undefined): void {
|
|
177
190
|
this.blockingAlertInfo = alertInfo;
|
|
178
191
|
}
|
|
@@ -0,0 +1,175 @@
|
|
|
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 { SDLCServerClient, User } from '@finos/legend-server-sdlc';
|
|
18
|
+
import {
|
|
19
|
+
type GeneratorFn,
|
|
20
|
+
assertErrorThrown,
|
|
21
|
+
HttpStatus,
|
|
22
|
+
LogEvent,
|
|
23
|
+
NetworkClientError,
|
|
24
|
+
type PlainObject,
|
|
25
|
+
} from '@finos/legend-shared';
|
|
26
|
+
import {
|
|
27
|
+
action,
|
|
28
|
+
computed,
|
|
29
|
+
flow,
|
|
30
|
+
flowResult,
|
|
31
|
+
makeObservable,
|
|
32
|
+
observable,
|
|
33
|
+
} from 'mobx';
|
|
34
|
+
import { APPLICATION_EVENT } from './ApplicationEvent.js';
|
|
35
|
+
import {
|
|
36
|
+
type GenericLegendApplicationStore,
|
|
37
|
+
ActionAlertActionType,
|
|
38
|
+
ActionAlertType,
|
|
39
|
+
} from './ApplicationStore.js';
|
|
40
|
+
|
|
41
|
+
export class LegendApplicationSDLCSetupState {
|
|
42
|
+
applicationStore: GenericLegendApplicationStore;
|
|
43
|
+
sdlcServerClient: SDLCServerClient;
|
|
44
|
+
isSDLCAuthorized = false;
|
|
45
|
+
SDLCServerTermsOfServicesUrlsToView: string[] = [];
|
|
46
|
+
|
|
47
|
+
constructor(
|
|
48
|
+
applicationStore: GenericLegendApplicationStore,
|
|
49
|
+
sdlcServerClient: SDLCServerClient,
|
|
50
|
+
) {
|
|
51
|
+
makeObservable(this, {
|
|
52
|
+
isSDLCAuthorized: observable,
|
|
53
|
+
SDLCServerTermsOfServicesUrlsToView: observable,
|
|
54
|
+
dismissSDLCServerTermsOfServicesAlert: action,
|
|
55
|
+
needsToAcceptSDLCServerTermsOfServices: computed,
|
|
56
|
+
initializeSDLCServerClient: flow,
|
|
57
|
+
fetchCurrentUser: flow,
|
|
58
|
+
});
|
|
59
|
+
this.applicationStore = applicationStore;
|
|
60
|
+
this.sdlcServerClient = sdlcServerClient;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
*initializeSDLCServerClient(): GeneratorFn<void> {
|
|
64
|
+
try {
|
|
65
|
+
this.isSDLCAuthorized =
|
|
66
|
+
(yield this.sdlcServerClient.isAuthorized()) as boolean;
|
|
67
|
+
if (!this.isSDLCAuthorized) {
|
|
68
|
+
this.applicationStore.navigator.jumpTo(
|
|
69
|
+
SDLCServerClient.authorizeCallbackUrl(
|
|
70
|
+
this.sdlcServerClient.baseUrl ?? '',
|
|
71
|
+
this.applicationStore.navigator.getCurrentLocation(),
|
|
72
|
+
),
|
|
73
|
+
);
|
|
74
|
+
} else {
|
|
75
|
+
// Only proceed intialization after passing authorization check
|
|
76
|
+
|
|
77
|
+
// check terms of service agreement status
|
|
78
|
+
this.SDLCServerTermsOfServicesUrlsToView =
|
|
79
|
+
(yield this.sdlcServerClient.hasAcceptedTermsOfService()) as string[];
|
|
80
|
+
if (this.SDLCServerTermsOfServicesUrlsToView.length) {
|
|
81
|
+
this.applicationStore.setActionAlertInfo({
|
|
82
|
+
message: `Please read and accept the SDLC servers' terms of service`,
|
|
83
|
+
prompt: `Click 'Done' when you have accepted all the terms`,
|
|
84
|
+
type: ActionAlertType.CAUTION,
|
|
85
|
+
actions: [
|
|
86
|
+
{
|
|
87
|
+
label: 'See terms of services',
|
|
88
|
+
default: true,
|
|
89
|
+
handler: (): void =>
|
|
90
|
+
this.SDLCServerTermsOfServicesUrlsToView.forEach((url) =>
|
|
91
|
+
this.applicationStore.navigator.openNewWindow(url),
|
|
92
|
+
),
|
|
93
|
+
type: ActionAlertActionType.PROCEED,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
label: 'Done',
|
|
97
|
+
type: ActionAlertActionType.PROCEED_WITH_CAUTION,
|
|
98
|
+
handler: (): void => {
|
|
99
|
+
this.dismissSDLCServerTermsOfServicesAlert();
|
|
100
|
+
this.applicationStore.navigator.reload();
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// fetch server features config + current user
|
|
108
|
+
yield this.sdlcServerClient.fetchServerFeaturesConfiguration();
|
|
109
|
+
yield flowResult(this.fetchCurrentUser());
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
assertErrorThrown(error);
|
|
113
|
+
if (
|
|
114
|
+
// eslint-disable-next-line no-process-env
|
|
115
|
+
process.env.NODE_ENV === 'development' &&
|
|
116
|
+
error instanceof NetworkClientError &&
|
|
117
|
+
error.response.status === HttpStatus.UNAUTHORIZED
|
|
118
|
+
) {
|
|
119
|
+
this.applicationStore.setActionAlertInfo({
|
|
120
|
+
message:
|
|
121
|
+
'The first time the application starts in development mode, the developer would need to authenticate using SDLC server. Please do so then manually reload the app',
|
|
122
|
+
type: ActionAlertType.STANDARD,
|
|
123
|
+
actions: [
|
|
124
|
+
{
|
|
125
|
+
label: 'Authenticate using SDLC',
|
|
126
|
+
type: ActionAlertActionType.PROCEED,
|
|
127
|
+
default: true,
|
|
128
|
+
handler: (): void => {
|
|
129
|
+
this.applicationStore.navigator.openNewWindow(
|
|
130
|
+
this.sdlcServerClient.currentUserUrl,
|
|
131
|
+
);
|
|
132
|
+
this.applicationStore.setBlockingAlert({
|
|
133
|
+
message:
|
|
134
|
+
'Waiting for the developer to authenticate using SDLC server',
|
|
135
|
+
prompt:
|
|
136
|
+
'Please manually reload the application after authentication',
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
} else {
|
|
143
|
+
this.applicationStore.log.error(
|
|
144
|
+
LogEvent.create(APPLICATION_EVENT.APPLICATION_SETUP_FAILURE),
|
|
145
|
+
error,
|
|
146
|
+
);
|
|
147
|
+
this.applicationStore.notifyError(error);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
*fetchCurrentUser(): GeneratorFn<void> {
|
|
153
|
+
try {
|
|
154
|
+
const currentUser = User.serialization.fromJson(
|
|
155
|
+
(yield this.sdlcServerClient.getCurrentUser()) as PlainObject<User>,
|
|
156
|
+
);
|
|
157
|
+
this.sdlcServerClient.setCurrentUser(currentUser);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
assertErrorThrown(error);
|
|
160
|
+
this.applicationStore.log.error(
|
|
161
|
+
LogEvent.create(APPLICATION_EVENT.APPLICATION_SETUP_FAILURE),
|
|
162
|
+
error,
|
|
163
|
+
);
|
|
164
|
+
this.applicationStore.notifyWarning(error.message);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
get needsToAcceptSDLCServerTermsOfServices(): boolean {
|
|
169
|
+
return Boolean(this.SDLCServerTermsOfServicesUrlsToView.length);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
dismissSDLCServerTermsOfServicesAlert(): void {
|
|
173
|
+
this.SDLCServerTermsOfServicesUrlsToView = [];
|
|
174
|
+
}
|
|
175
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"./src/stores/DocumentationService.ts",
|
|
42
42
|
"./src/stores/EventService.ts",
|
|
43
43
|
"./src/stores/LegendApplicationPlugin.ts",
|
|
44
|
+
"./src/stores/LegendApplicationSDLCSetupState.ts",
|
|
44
45
|
"./src/stores/PureLanguageSupport.ts",
|
|
45
46
|
"./src/stores/WebApplicationNavigator.ts",
|
|
46
47
|
"./src/stores/shared/ExecutionPlanState.ts",
|