@finos/legend-application 8.0.2 → 9.0.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.
Files changed (123) hide show
  1. package/lib/components/LegendApplicationComponentFrameworkProvider.d.ts +4 -2
  2. package/lib/components/LegendApplicationComponentFrameworkProvider.d.ts.map +1 -1
  3. package/lib/components/LegendApplicationComponentFrameworkProvider.js +7 -4
  4. package/lib/components/LegendApplicationComponentFrameworkProvider.js.map +1 -1
  5. package/lib/components/NotificationManager.js +1 -1
  6. package/lib/components/NotificationManager.js.map +1 -1
  7. package/lib/components/WebApplicationNavigatorProvider.d.ts.map +1 -1
  8. package/lib/components/WebApplicationNavigatorProvider.js +1 -1
  9. package/lib/components/WebApplicationNavigatorProvider.js.map +1 -1
  10. package/lib/components/{shared/execution-plan-viewer → execution-plan-viewer}/ExecutionPlanViewer.d.ts +1 -1
  11. package/lib/components/execution-plan-viewer/ExecutionPlanViewer.d.ts.map +1 -0
  12. package/lib/components/{shared/execution-plan-viewer → execution-plan-viewer}/ExecutionPlanViewer.js +3 -3
  13. package/lib/components/execution-plan-viewer/ExecutionPlanViewer.js.map +1 -0
  14. package/lib/components/{shared/execution-plan-viewer → execution-plan-viewer}/SQLExecutionNodeViewer.d.ts +1 -1
  15. package/lib/components/execution-plan-viewer/SQLExecutionNodeViewer.d.ts.map +1 -0
  16. package/lib/components/{shared/execution-plan-viewer → execution-plan-viewer}/SQLExecutionNodeViewer.js +2 -2
  17. package/lib/components/execution-plan-viewer/SQLExecutionNodeViewer.js.map +1 -0
  18. package/lib/components/shared/DocumentationLink.d.ts +5 -0
  19. package/lib/components/shared/DocumentationLink.d.ts.map +1 -1
  20. package/lib/components/shared/DocumentationLink.js +12 -2
  21. package/lib/components/shared/DocumentationLink.js.map +1 -1
  22. package/lib/components/shared/{PackageableElementOptionRenderer.d.ts → PackageableElementOptionLabel.d.ts} +1 -1
  23. package/lib/components/shared/PackageableElementOptionLabel.d.ts.map +1 -0
  24. package/lib/components/shared/{PackageableElementOptionRenderer.js → PackageableElementOptionLabel.js} +5 -5
  25. package/lib/components/shared/PackageableElementOptionLabel.js.map +1 -0
  26. package/lib/components/shared/TextInputEditor.d.ts.map +1 -1
  27. package/lib/components/shared/TextInputEditor.js +1 -2
  28. package/lib/components/shared/TextInputEditor.js.map +1 -1
  29. package/lib/index.css +2 -2
  30. package/lib/index.css.map +1 -1
  31. package/lib/index.d.ts +8 -9
  32. package/lib/index.d.ts.map +1 -1
  33. package/lib/index.js +8 -9
  34. package/lib/index.js.map +1 -1
  35. package/lib/stores/ApplicationStore.d.ts +2 -0
  36. package/lib/stores/ApplicationStore.d.ts.map +1 -1
  37. package/lib/stores/ApplicationStore.js +13 -10
  38. package/lib/stores/ApplicationStore.js.map +1 -1
  39. package/lib/stores/AssistantService.js +1 -1
  40. package/lib/stores/AssistantService.js.map +1 -1
  41. package/lib/stores/{shared/ExecutionPlanState.d.ts → ExecutionPlanState.d.ts} +1 -1
  42. package/lib/stores/ExecutionPlanState.d.ts.map +1 -0
  43. package/lib/stores/{shared/ExecutionPlanState.js → ExecutionPlanState.js} +0 -0
  44. package/lib/stores/ExecutionPlanState.js.map +1 -0
  45. package/lib/stores/LegendApplicationDocumentation.d.ts +2 -1
  46. package/lib/stores/LegendApplicationDocumentation.d.ts.map +1 -1
  47. package/lib/stores/LegendApplicationDocumentation.js +1 -0
  48. package/lib/stores/LegendApplicationDocumentation.js.map +1 -1
  49. package/lib/stores/WebApplicationNavigator.d.ts +62 -30
  50. package/lib/stores/WebApplicationNavigator.d.ts.map +1 -1
  51. package/lib/stores/WebApplicationNavigator.js +80 -15
  52. package/lib/stores/WebApplicationNavigator.js.map +1 -1
  53. package/lib/{components/ApplicationTestID.js → stores/WebApplicationRouter.d.ts} +4 -5
  54. package/lib/stores/WebApplicationRouter.d.ts.map +1 -0
  55. package/{src/components/ApplicationTestID.ts → lib/stores/WebApplicationRouter.js} +4 -4
  56. package/lib/stores/WebApplicationRouter.js.map +1 -0
  57. package/package.json +9 -11
  58. package/src/components/LegendApplicationComponentFrameworkProvider.tsx +18 -14
  59. package/src/components/NotificationManager.tsx +1 -1
  60. package/src/components/WebApplicationNavigatorProvider.tsx +1 -1
  61. package/src/components/{shared/execution-plan-viewer → execution-plan-viewer}/ExecutionPlanViewer.tsx +3 -3
  62. package/src/components/{shared/execution-plan-viewer → execution-plan-viewer}/SQLExecutionNodeViewer.tsx +3 -3
  63. package/src/components/shared/DocumentationLink.tsx +25 -1
  64. package/src/components/shared/{PackageableElementOptionRenderer.tsx → PackageableElementOptionLabel.tsx} +4 -4
  65. package/src/components/shared/TextInputEditor.tsx +1 -2
  66. package/src/index.ts +9 -9
  67. package/src/stores/ApplicationStore.ts +15 -12
  68. package/src/stores/AssistantService.ts +1 -1
  69. package/src/stores/{shared/ExecutionPlanState.ts → ExecutionPlanState.ts} +1 -1
  70. package/src/stores/LegendApplicationDocumentation.ts +1 -0
  71. package/src/stores/WebApplicationNavigator.ts +149 -39
  72. package/{lib/components/ApplicationTestID.d.ts → src/stores/WebApplicationRouter.ts} +12 -4
  73. package/tsconfig.json +7 -16
  74. package/lib/components/ApplicationTestID.d.ts.map +0 -1
  75. package/lib/components/ApplicationTestID.js.map +0 -1
  76. package/lib/components/shared/BasicValueSpecificationEditor.d.ts +0 -52
  77. package/lib/components/shared/BasicValueSpecificationEditor.d.ts.map +0 -1
  78. package/lib/components/shared/BasicValueSpecificationEditor.js +0 -323
  79. package/lib/components/shared/BasicValueSpecificationEditor.js.map +0 -1
  80. package/lib/components/shared/CustomDatePicker.d.ts +0 -38
  81. package/lib/components/shared/CustomDatePicker.d.ts.map +0 -1
  82. package/lib/components/shared/CustomDatePicker.js +0 -616
  83. package/lib/components/shared/CustomDatePicker.js.map +0 -1
  84. package/lib/components/shared/LambdaEditor.d.ts +0 -92
  85. package/lib/components/shared/LambdaEditor.d.ts.map +0 -1
  86. package/lib/components/shared/LambdaEditor.js +0 -434
  87. package/lib/components/shared/LambdaEditor.js.map +0 -1
  88. package/lib/components/shared/LambdaParameterValuesEditor.d.ts +0 -25
  89. package/lib/components/shared/LambdaParameterValuesEditor.d.ts.map +0 -1
  90. package/lib/components/shared/LambdaParameterValuesEditor.js +0 -52
  91. package/lib/components/shared/LambdaParameterValuesEditor.js.map +0 -1
  92. package/lib/components/shared/PackageableElementOptionRenderer.d.ts.map +0 -1
  93. package/lib/components/shared/PackageableElementOptionRenderer.js.map +0 -1
  94. package/lib/components/shared/execution-plan-viewer/ExecutionPlanViewer.d.ts.map +0 -1
  95. package/lib/components/shared/execution-plan-viewer/ExecutionPlanViewer.js.map +0 -1
  96. package/lib/components/shared/execution-plan-viewer/SQLExecutionNodeViewer.d.ts.map +0 -1
  97. package/lib/components/shared/execution-plan-viewer/SQLExecutionNodeViewer.js.map +0 -1
  98. package/lib/stores/CJS__Fuse.cjs +0 -35
  99. package/lib/stores/CJS__Fuse.cjs.map +0 -1
  100. package/lib/stores/CJS__Fuse.d.cts +0 -28
  101. package/lib/stores/CJS__Fuse.d.cts.map +0 -1
  102. package/lib/stores/shared/ExecutionPlanState.d.ts.map +0 -1
  103. package/lib/stores/shared/ExecutionPlanState.js.map +0 -1
  104. package/lib/stores/shared/LambdaEditorState.d.ts +0 -40
  105. package/lib/stores/shared/LambdaEditorState.d.ts.map +0 -1
  106. package/lib/stores/shared/LambdaEditorState.js +0 -81
  107. package/lib/stores/shared/LambdaEditorState.js.map +0 -1
  108. package/lib/stores/shared/LambdaParameterState.d.ts +0 -62
  109. package/lib/stores/shared/LambdaParameterState.d.ts.map +0 -1
  110. package/lib/stores/shared/LambdaParameterState.js +0 -160
  111. package/lib/stores/shared/LambdaParameterState.js.map +0 -1
  112. package/lib/stores/shared/ValueSpecificationModifierHelper.d.ts +0 -27
  113. package/lib/stores/shared/ValueSpecificationModifierHelper.d.ts.map +0 -1
  114. package/lib/stores/shared/ValueSpecificationModifierHelper.js +0 -49
  115. package/lib/stores/shared/ValueSpecificationModifierHelper.js.map +0 -1
  116. package/src/components/shared/BasicValueSpecificationEditor.tsx +0 -828
  117. package/src/components/shared/CustomDatePicker.tsx +0 -1292
  118. package/src/components/shared/LambdaEditor.tsx +0 -854
  119. package/src/components/shared/LambdaParameterValuesEditor.tsx +0 -118
  120. package/src/stores/CJS__Fuse.cts +0 -28
  121. package/src/stores/shared/LambdaEditorState.ts +0 -118
  122. package/src/stores/shared/LambdaParameterState.ts +0 -253
  123. package/src/stores/shared/ValueSpecificationModifierHelper.ts +0 -104
@@ -14,24 +14,28 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { LegendStyleProvider } from '@finos/legend-art';
17
+ import { Backdrop, LegendStyleProvider } from '@finos/legend-art';
18
+ import { observer } from 'mobx-react-lite';
18
19
  import { DndProvider } from 'react-dnd';
19
20
  import { HTML5Backend } from 'react-dnd-html5-backend';
20
21
  import { ActionAlert } from './ActionAlert.js';
22
+ import { useApplicationStore } from './ApplicationStoreProvider.js';
21
23
  import { BlockingAlert } from './BlockingAlert.js';
22
24
  import { NotificationManager } from './NotificationManager.js';
23
25
 
24
- export const LegendApplicationComponentFrameworkProvider: React.FC<{
25
- children: React.ReactNode;
26
- }> = (props) => {
27
- const { children } = props;
26
+ export const LegendApplicationComponentFrameworkProvider = observer(
27
+ (props: { children: React.ReactNode }) => {
28
+ const { children } = props;
29
+ const applicationStore = useApplicationStore();
28
30
 
29
- return (
30
- <LegendStyleProvider>
31
- <BlockingAlert />
32
- <ActionAlert />
33
- <NotificationManager />
34
- <DndProvider backend={HTML5Backend}>{children}</DndProvider>
35
- </LegendStyleProvider>
36
- );
37
- };
31
+ return (
32
+ <LegendStyleProvider>
33
+ <BlockingAlert />
34
+ <ActionAlert />
35
+ <NotificationManager />
36
+ <Backdrop className="backdrop" open={applicationStore.showBackdrop} />
37
+ <DndProvider backend={HTML5Backend}>{children}</DndProvider>
38
+ </LegendStyleProvider>
39
+ );
40
+ },
41
+ );
@@ -164,7 +164,7 @@ export const NotificationManager = observer(() => {
164
164
  key="close"
165
165
  onClick={handleClose}
166
166
  tabIndex={-1}
167
- title={'Dismiss'}
167
+ title="Dismiss"
168
168
  >
169
169
  <TimesIcon />
170
170
  </button>,
@@ -17,9 +17,9 @@
17
17
  import { guaranteeNonNullable } from '@finos/legend-shared';
18
18
  import { useLocalObservable } from 'mobx-react-lite';
19
19
  import { createContext, useContext } from 'react';
20
- import { useHistory } from 'react-router';
21
20
  import type { History } from 'history';
22
21
  import { WebApplicationNavigator } from '../stores/WebApplicationNavigator.js';
22
+ import { useHistory } from 'react-router';
23
23
 
24
24
  const WebApplicationNavigatorContext = createContext<
25
25
  WebApplicationNavigator | undefined
@@ -43,7 +43,7 @@ import {
43
43
  ExecutionPlanViewTreeNodeData,
44
44
  EXECUTION_PLAN_VIEW_MODE,
45
45
  type ExecutionPlanState,
46
- } from '../../../stores/shared/ExecutionPlanState.js';
46
+ } from '../../stores/ExecutionPlanState.js';
47
47
  import { observer } from 'mobx-react-lite';
48
48
  import {
49
49
  ExecutionPlan,
@@ -52,8 +52,8 @@ import {
52
52
  RelationalTDSInstantiationExecutionNode,
53
53
  type RawExecutionPlan,
54
54
  } from '@finos/legend-graph';
55
- import { EDITOR_LANGUAGE, TAB_SIZE } from '../../../const.js';
56
- import { TextInputEditor } from '../TextInputEditor.js';
55
+ import { EDITOR_LANGUAGE, TAB_SIZE } from '../../const.js';
56
+ import { TextInputEditor } from '../shared/TextInputEditor.js';
57
57
  import { SQLExecutionNodeViewer } from './SQLExecutionNodeViewer.js';
58
58
 
59
59
  /**
@@ -15,11 +15,11 @@
15
15
  */
16
16
 
17
17
  import { observer } from 'mobx-react-lite';
18
- import type { ExecutionPlanState } from '../../../stores/shared/ExecutionPlanState.js';
18
+ import type { ExecutionPlanState } from '../../stores/ExecutionPlanState.js';
19
19
  import { format } from 'sql-formatter';
20
20
  import type { SQLResultColumn } from '@finos/legend-graph';
21
- import { TextInputEditor } from '../TextInputEditor.js';
22
- import { EDITOR_LANGUAGE } from '../../../const.js';
21
+ import { TextInputEditor } from '../shared/TextInputEditor.js';
22
+ import { EDITOR_LANGUAGE } from '../../const.js';
23
23
 
24
24
  /**
25
25
  * TODO: Create a new `AbstractPlugin` for this, called `ExecutionPlanViewerPlugin`
@@ -33,7 +33,7 @@ export const DocumentationLink: React.FC<{
33
33
  documentationKey,
34
34
  );
35
35
  } else if (documentationEntry.url) {
36
- applicationStore.navigator.openNewWindow(documentationEntry.url);
36
+ applicationStore.navigator.visitAddress(documentationEntry.url);
37
37
  }
38
38
  }
39
39
  };
@@ -53,3 +53,27 @@ export const DocumentationLink: React.FC<{
53
53
  />
54
54
  );
55
55
  };
56
+
57
+ export const DocumentationPreview: React.FC<{
58
+ text?: string | undefined;
59
+ documentationKey: string;
60
+ className?: string | undefined;
61
+ }> = (props) => {
62
+ const { documentationKey, text, className } = props;
63
+ const applicationStore = useApplicationStore();
64
+ const documentationEntry =
65
+ applicationStore.documentationService.getDocEntry(documentationKey);
66
+ const textContent = text ?? documentationEntry?.text;
67
+
68
+ if (!documentationEntry || !textContent) {
69
+ return null;
70
+ }
71
+ return (
72
+ <div className={clsx('documentation-preview', className)}>
73
+ <div className="documentation-preview__text">{textContent}</div>
74
+ <div className="documentation-preview__hint">
75
+ <DocumentationLink documentationKey={documentationKey} />
76
+ </div>
77
+ </div>
78
+ );
79
+ };
@@ -51,17 +51,17 @@ export const getPackageableElementOptionFormatter = (props: {
51
51
  option: PackageableElementOption<PackageableElement>,
52
52
  ): React.ReactNode {
53
53
  const className = props.darkMode
54
- ? 'packageable-element-format-option-label--dark'
55
- : 'packageable-element-format-option-label';
54
+ ? 'packageable-element-option-label--dark'
55
+ : 'packageable-element-option-label';
56
56
  const colorCode = getElementColorCode(option.value);
57
57
 
58
58
  return (
59
59
  <div className={className}>
60
60
  <div
61
61
  title={generateOptionTooltipText(option.value)}
62
- className={`packageable-element-format-option-label-type ${
62
+ className={`packageable-element-option-label__type ${
63
63
  colorCode
64
- ? `packageable-element-format-option-label-type--${colorCode}`
64
+ ? `packageable-element-option-label__type--${colorCode}`
65
65
  : ''
66
66
  } `}
67
67
  ></div>
@@ -20,7 +20,6 @@ import {
20
20
  type IKeyboardEvent,
21
21
  editor as monacoEditorAPI,
22
22
  } from 'monaco-editor';
23
- import { useResizeDetector } from 'react-resize-detector';
24
23
  import {
25
24
  disposeEditor,
26
25
  disableEditorHotKeys,
@@ -28,6 +27,7 @@ import {
28
27
  resetLineNumberGutterWidth,
29
28
  getEditorValue,
30
29
  normalizeLineEnding,
30
+ useResizeDetector,
31
31
  } from '@finos/legend-art';
32
32
  import { type EDITOR_LANGUAGE, EDITOR_THEME, TAB_SIZE } from '../../const.js';
33
33
  import { useApplicationStore } from '../ApplicationStoreProvider.js';
@@ -78,7 +78,6 @@ export const TextInputEditor: React.FC<{
78
78
  */
79
79
  const value = normalizeLineEnding(inputValue);
80
80
  const textInputRef = useRef<HTMLDivElement>(null);
81
-
82
81
  const { ref, width, height } = useResizeDetector<HTMLDivElement>();
83
82
 
84
83
  useEffect(() => {
package/src/index.ts CHANGED
@@ -41,21 +41,21 @@ export * from './stores/LegendApplicationPlugin.js';
41
41
 
42
42
  export * from './components/shared/TextSearchAdvancedConfigMenu.js';
43
43
  export * from './stores/shared/TextSearchAdvancedConfigState.js';
44
+ export * from './stores/LegendApplicationDocumentation.js';
44
45
 
45
46
  export * from './stores/ApplicationStoreTestUtils.js';
47
+ export * from './stores/WebApplicationRouter.js';
46
48
 
47
49
  // ------------------------------------------- Shared components -------------------------------------------
48
50
 
49
51
  export * from './components/shared/DocumentationLink.js';
50
52
  export * from './components/shared/TextInputEditor.js';
51
- export * from './components/shared/LambdaEditor.js';
52
- export * from './components/shared/BasicValueSpecificationEditor.js';
53
- export * from './components/shared/LambdaParameterValuesEditor.js';
54
- export * from './components/shared/PackageableElementOptionRenderer.js';
55
- export * from './components/shared/execution-plan-viewer/ExecutionPlanViewer.js';
53
+ export * from './components/shared/PackageableElementOptionLabel.js';
56
54
 
57
- export { LambdaEditorState } from './stores/shared/LambdaEditorState.js';
58
55
  export * from './stores/shared/PackageableElementOption.js';
59
- export * from './stores/shared/LambdaParameterState.js';
60
- export * from './stores/shared/ValueSpecificationModifierHelper.js';
61
- export * from './stores/shared/ExecutionPlanState.js';
56
+
57
+ /**
58
+ * @modularize
59
+ */
60
+ export * from './components/execution-plan-viewer/ExecutionPlanViewer.js';
61
+ export * from './stores/ExecutionPlanState.js';
@@ -136,6 +136,9 @@ export class ApplicationStore<
136
136
  telemetryService = new TelemetryService();
137
137
  tracerService = new TracerService();
138
138
 
139
+ // misc
140
+ showBackdrop = false;
141
+
139
142
  // theme
140
143
  /**
141
144
  * NOTE: this is the poor man way of doing theming
@@ -150,6 +153,8 @@ export class ApplicationStore<
150
153
  blockingAlertInfo: observable,
151
154
  actionAlertInfo: observable,
152
155
  TEMPORARY__isLightThemeEnabled: observable,
156
+ showBackdrop: observable,
157
+ setShowBackdrop: action,
153
158
  setBlockingAlert: action,
154
159
  setActionAlertInfo: action,
155
160
  setNotification: action,
@@ -185,6 +190,10 @@ export class ApplicationStore<
185
190
  this.TEMPORARY__isLightThemeEnabled = val;
186
191
  }
187
192
 
193
+ setShowBackdrop(val: boolean): void {
194
+ this.showBackdrop = val;
195
+ }
196
+
188
197
  setBlockingAlert(alertInfo: BlockingAlertInfo | undefined): void {
189
198
  this.blockingAlertInfo = alertInfo;
190
199
  }
@@ -335,18 +344,12 @@ export class ApplicationStore<
335
344
  };
336
345
 
337
346
  async copyTextToClipboard(text: string): Promise<void> {
338
- if (
339
- typeof navigator.clipboard === 'object' &&
340
- typeof navigator.clipboard.writeText === 'function'
341
- ) {
342
- // This is a much cleaner way which requires HTTPS
343
- // See https://developers.google.com/web/updates/2018/03/clipboardapi
344
- await navigator.clipboard.writeText(text).catch((error) => {
345
- this.notifyError(error);
346
- });
347
- return;
348
- }
349
- this.notifyError('Browser does not support clipboard functionality');
347
+ // This is a much cleaner way which requires HTTPS
348
+ // See https://developers.google.com/web/updates/2018/03/clipboardapi
349
+ await navigator.clipboard.writeText(text).catch((error) => {
350
+ this.notifyError(error);
351
+ });
352
+ return;
350
353
  }
351
354
 
352
355
  notifyUnsupportedFeature(featureName: string): void {
@@ -17,7 +17,7 @@
17
17
  import { action, makeObservable, observable, computed } from 'mobx';
18
18
  import type { DocumentationEntry } from './DocumentationService.js';
19
19
  import type { GenericLegendApplicationStore } from './ApplicationStore.js';
20
- import { Fuse } from './CJS__Fuse.cjs';
20
+ import { Fuse } from '@finos/legend-art';
21
21
  import {
22
22
  type MarkdownText,
23
23
  guaranteeNonEmptyString,
@@ -21,7 +21,7 @@ import {
21
21
  ExecutionPlan,
22
22
  ExecutionNode,
23
23
  } from '@finos/legend-graph';
24
- import type { GenericLegendApplicationStore } from '../ApplicationStore.js';
24
+ import type { GenericLegendApplicationStore } from './ApplicationStore.js';
25
25
  import type { TreeNodeData } from '@finos/legend-art';
26
26
 
27
27
  export class ExecutionPlanViewTreeNodeData implements TreeNodeData {
@@ -16,4 +16,5 @@
16
16
 
17
17
  export enum LEGEND_APPLICATION_DOCUMENTATION_KEY {
18
18
  QUESTION_HOW_TO_USE_ADVANCED_SEARCH_SYNTAX = 'question.how-to-use-advanced-search-syntax',
19
+ QUESTION_WHEN_TO_CONFIGURE_PLATFORM_VERSIONS = 'question.when-to-configure-project-platform-dependencies-versions',
19
20
  }
@@ -16,44 +16,102 @@
16
16
 
17
17
  import type { History } from 'history';
18
18
  import { guaranteeNonNullable } from '@finos/legend-shared';
19
+ import { action, computed, makeObservable, observable } from 'mobx';
20
+
21
+ type Location = string;
22
+ type Address = string;
19
23
 
20
24
  /**
21
- * This is an initial attempt to try to generalize the application
22
- * to other platforms. But regardless, this is more convenient for testing.
25
+ * This is an initial attempt to generalize the application navigation to other platforms
23
26
  *
24
- * NOTE: this is **NOT** the right way to do this. Our intention here is to make
27
+ * NOTE: this might **NOT** be the right way to do this. Our intention here is to make
25
28
  * app navigator something generic enough so we are somewhat platform-agnostic
26
29
  * i.e. browser, electron, PC, UNIX, etc.
27
30
  *
28
- * Parameterize on the type of the location might not be the best thing to do.
29
- * Because typing wise, this forces us to also parameterize consumers of this,
30
- * which is `ApplicationStore`. It means that we must dictate in the source
31
- * code the platform the app depends on, clearly for web browser, `string` is the
32
- * easy option, but if we do so, it defeats the purpose of this abstraction in the
33
- * first place.
34
- *
35
- * As such, instead, we should design a more generic concept `Location` to pass around.
36
- * We would need to flesh out the details, but this is the rough idea.
37
- *
38
- * Another thought is that we should also generalize Router so it handles more than just
31
+ * We should design a more advanced concept `Location` to pass around.
32
+ * Also, we should also generalize Router so it handles more than just
39
33
  * URLs. If we make `router` and `navigator` work together, we can potentially generalize
40
34
  * application navigation
41
35
  *
42
36
  * However, this depends on how and when we move to another platform, like `electron` for example
43
37
  * See https://github.com/finos/legend-studio/issues/718
44
38
  */
45
- interface ApplicationNavigator<T> {
39
+ interface ApplicationNavigator {
40
+ /**
41
+ * Navigate to the specified location
42
+ */
43
+ goToLocation(location: Location): void;
44
+
45
+ /**
46
+ * Navigate to the specified location and reload the application
47
+ */
48
+ reloadToLocation(
49
+ location: Location,
50
+ options?: { ignoreBlocking?: boolean | undefined },
51
+ ): void;
52
+
53
+ /**
54
+ * Reload the application using the same address
55
+ */
46
56
  reload(): void;
47
- goTo(location: T): void;
48
- jumpTo(location: T): void;
49
- openNewWindow(location: T): void;
50
- getCurrentLocation(): T;
51
- getCurrentLocationPath(): T;
52
- generateLocation(locationPath: T): T;
57
+
58
+ /**
59
+ * Visit the specified address
60
+ *
61
+ * NOTE: unless specified, the visit will be done in a new window
62
+ */
63
+ visitAddress(
64
+ address: Address,
65
+ options?: {
66
+ useSameWindow?: boolean | undefined;
67
+ },
68
+ ): void;
69
+
70
+ getCurrentAddress(): Address;
71
+ getCurrentLocation(): Location;
72
+ generateAddress(location: Location): Address;
73
+
74
+ /**
75
+ * Disable platform native navigation feature
76
+ *
77
+ * e.g. in web browser, we will block back/forward buttons
78
+ */
79
+ blockPlatformNavigation(blockCheckers: (() => boolean)[]): void;
80
+ unblockPlatformNavigation(): void;
81
+ get isPlatformNavigationBlocked(): boolean;
53
82
  }
54
83
 
55
- export class WebApplicationNavigator implements ApplicationNavigator<string> {
84
+ export class WebApplicationNavigator implements ApplicationNavigator {
56
85
  private readonly historyAPI: History;
86
+ private _isPlatformNavigationBlocked = false;
87
+ private _forceBypassPlatformNavigationBlocking = false;
88
+ private _blockCheckers: (() => boolean)[] = [];
89
+ private _beforeUnloadListener = (event: BeforeUnloadEvent): void => {
90
+ if (this._forceBypassPlatformNavigationBlocking) {
91
+ return;
92
+ }
93
+ if (this._blockCheckers.some((checker) => checker())) {
94
+ // NOTE: there is no way to customize the alert message for now since Chrome removed support for it due to security concerns
95
+ // See https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload#Browser_compatibility
96
+ event.returnValue = '';
97
+ }
98
+ };
99
+
100
+ notifier?: ((message: string) => void) | undefined;
101
+
102
+ constructor(historyApiClient: History) {
103
+ makeObservable<WebApplicationNavigator, '_isPlatformNavigationBlocked'>(
104
+ this,
105
+ {
106
+ _isPlatformNavigationBlocked: observable,
107
+ isPlatformNavigationBlocked: computed,
108
+ blockPlatformNavigation: action,
109
+ unblockPlatformNavigation: action,
110
+ },
111
+ );
112
+
113
+ this.historyAPI = historyApiClient;
114
+ }
57
115
 
58
116
  private get window(): Window {
59
117
  return guaranteeNonNullable(
@@ -62,38 +120,90 @@ export class WebApplicationNavigator implements ApplicationNavigator<string> {
62
120
  );
63
121
  }
64
122
 
65
- constructor(historyApiClient: History) {
66
- this.historyAPI = historyApiClient;
67
- }
68
-
69
- reload(): void {
70
- this.window.location.reload();
123
+ goToLocation(location: Location): void {
124
+ this.historyAPI.push(location);
71
125
  }
72
126
 
73
- goTo(location: string): void {
74
- this.historyAPI.push(location);
127
+ reloadToLocation(
128
+ location: Location,
129
+ options?: { ignoreBlocking?: boolean | undefined },
130
+ ): void {
131
+ if (options?.ignoreBlocking) {
132
+ this._forceBypassPlatformNavigationBlocking = true;
133
+ }
134
+ // if (
135
+ // this._isPlatformNavigationBlocked &&
136
+ // !this._forceBypassPlatformNavigationBlocking
137
+ // ) {
138
+ // this.notifier
139
+ // return;
140
+ // }
141
+ this.window.location.href = this.generateAddress(location);
75
142
  }
76
143
 
77
- jumpTo(location: string): void {
78
- this.window.location.href = location;
144
+ reload(options?: { ignoreBlocking?: boolean | undefined }): void {
145
+ if (options?.ignoreBlocking) {
146
+ this._forceBypassPlatformNavigationBlocking = true;
147
+ }
148
+ this.window.location.reload();
79
149
  }
80
150
 
81
- openNewWindow(location: string): void {
82
- this.window.open(location, '_blank');
151
+ visitAddress(
152
+ address: Address,
153
+ options?: {
154
+ useSameWindow?: boolean | undefined;
155
+ },
156
+ ): void {
157
+ if (options?.useSameWindow) {
158
+ this.window.location.href = address;
159
+ } else {
160
+ this.window.open(address, '_blank');
161
+ }
83
162
  }
84
163
 
85
- getCurrentLocation(): string {
164
+ getCurrentAddress(): Address {
86
165
  return this.window.location.href;
87
166
  }
88
167
 
89
- getCurrentLocationPath(): string {
168
+ getCurrentLocation(): Location {
90
169
  return this.historyAPI.location.pathname;
91
170
  }
92
171
 
93
- generateLocation(locationPath: string): string {
172
+ generateAddress(location: Location): string {
94
173
  return (
95
- window.location.origin +
96
- this.historyAPI.createHref({ pathname: locationPath })
174
+ this.window.location.origin +
175
+ this.historyAPI.createHref({ pathname: location })
97
176
  );
98
177
  }
178
+
179
+ blockPlatformNavigation(blockCheckers: (() => boolean)[]): void {
180
+ this._isPlatformNavigationBlocked = true;
181
+
182
+ // Here we attempt to cancel the effect of the back button
183
+ // See https://medium.com/codex/angular-guards-disabling-browsers-back-button-for-specific-url-fdf05d9fe155#4f13
184
+ // This makes the current location the last entry in the browser history and clears any forward history
185
+ this.window.history.pushState(null, '', this.getCurrentAddress());
186
+ // The popstate event is triggered every time the user clicks back/forward button, but the forward history
187
+ // has been cleared, and now if we go back, we call `history.forward()`, which go 1 page forward,
188
+ // but there's no page forward, so effectively, the user remains on the same page
189
+ this.window.onpopstate = () => {
190
+ window.history.forward();
191
+ };
192
+
193
+ // Block browser navigation: e.g. reload, setting `window.href` directly, etc.
194
+ this._blockCheckers = blockCheckers;
195
+ this.window.removeEventListener('beforeunload', this._beforeUnloadListener);
196
+ this.window.addEventListener('beforeunload', this._beforeUnloadListener);
197
+ }
198
+
199
+ unblockPlatformNavigation(): void {
200
+ this._isPlatformNavigationBlocked = false;
201
+ this.window.onpopstate = null;
202
+ this._blockCheckers = [];
203
+ this.window.removeEventListener('beforeunload', this._beforeUnloadListener);
204
+ }
205
+
206
+ get isPlatformNavigationBlocked(): boolean {
207
+ return this._isPlatformNavigationBlocked;
208
+ }
99
209
  }
@@ -13,7 +13,15 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- export declare enum APPLICATION_TEST_ID {
17
- LAMBDA_EDITOR__EDITOR_INPUT = "lambda-editor__editor__input"
18
- }
19
- //# sourceMappingURL=ApplicationTestID.d.ts.map
16
+
17
+ export { BrowserRouter } from 'react-router-dom';
18
+ export {
19
+ Router,
20
+ Route,
21
+ Switch,
22
+ Redirect,
23
+ useParams,
24
+ generatePath,
25
+ MemoryRouter,
26
+ } from 'react-router';
27
+ export { createMemoryHistory } from 'history';
package/tsconfig.json CHANGED
@@ -31,7 +31,6 @@
31
31
  "./src/const.ts",
32
32
  "./src/index.ts",
33
33
  "./src/application/LegendApplicationConfig.ts",
34
- "./src/components/ApplicationTestID.ts",
35
34
  "./src/stores/ApplicationEvent.ts",
36
35
  "./src/stores/ApplicationNavigationContextService.ts",
37
36
  "./src/stores/ApplicationStore.ts",
@@ -40,16 +39,14 @@
40
39
  "./src/stores/AssistantService.ts",
41
40
  "./src/stores/DocumentationService.ts",
42
41
  "./src/stores/EventService.ts",
42
+ "./src/stores/ExecutionPlanState.ts",
43
43
  "./src/stores/LegendApplicationDocumentation.ts",
44
44
  "./src/stores/LegendApplicationPlugin.ts",
45
45
  "./src/stores/PureLanguageSupport.ts",
46
46
  "./src/stores/WebApplicationNavigator.ts",
47
- "./src/stores/shared/ExecutionPlanState.ts",
48
- "./src/stores/shared/LambdaEditorState.ts",
49
- "./src/stores/shared/LambdaParameterState.ts",
47
+ "./src/stores/WebApplicationRouter.ts",
50
48
  "./src/stores/shared/PackageableElementOption.ts",
51
49
  "./src/stores/shared/TextSearchAdvancedConfigState.ts",
52
- "./src/stores/shared/ValueSpecificationModifierHelper.ts",
53
50
  "./src/application/LegendApplication.tsx",
54
51
  "./src/application/LegendApplicationPluginManager.tsx",
55
52
  "./src/components/ActionAlert.tsx",
@@ -62,23 +59,17 @@
62
59
  "./src/components/VirtualAssistant.tsx",
63
60
  "./src/components/WebApplicationNavigatorProvider.tsx",
64
61
  "./src/components/WebApplicationNavigatorProviderTestUtils.tsx",
65
- "./src/components/shared/BasicValueSpecificationEditor.tsx",
66
- "./src/components/shared/CustomDatePicker.tsx",
62
+ "./src/components/execution-plan-viewer/ExecutionPlanViewer.tsx",
63
+ "./src/components/execution-plan-viewer/SQLExecutionNodeViewer.tsx",
67
64
  "./src/components/shared/DocumentationLink.tsx",
68
- "./src/components/shared/LambdaEditor.tsx",
69
- "./src/components/shared/LambdaParameterValuesEditor.tsx",
70
- "./src/components/shared/PackageableElementOptionRenderer.tsx",
65
+ "./src/components/shared/PackageableElementOptionLabel.tsx",
71
66
  "./src/components/shared/TextInputEditor.tsx",
72
- "./src/components/shared/TextSearchAdvancedConfigMenu.tsx",
73
- "./src/components/shared/execution-plan-viewer/ExecutionPlanViewer.tsx",
74
- "./src/components/shared/execution-plan-viewer/SQLExecutionNodeViewer.tsx",
75
- "./src/stores/CJS__Fuse.cts"
67
+ "./src/components/shared/TextSearchAdvancedConfigMenu.tsx"
76
68
  ],
77
69
  "include": [
78
70
  "src/**/*.ts",
79
71
  "src/**/*.tsx",
80
- "src/**/*.json",
81
- "src/**/*.cts"
72
+ "src/**/*.json"
82
73
  ],
83
74
  "exclude": [
84
75
  "src/**/__tests__/**/*.*",
@@ -1 +0,0 @@
1
- {"version":3,"file":"ApplicationTestID.d.ts","sourceRoot":"","sources":["../../src/components/ApplicationTestID.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,oBAAY,mBAAmB;IAC7B,2BAA2B,iCAAiC;CAC7D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ApplicationTestID.js","sourceRoot":"","sources":["../../src/components/ApplicationTestID.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAN,IAAY,mBAEX;AAFD,WAAY,mBAAmB;IAC7B,mFAA4D,CAAA;AAC9D,CAAC,EAFW,mBAAmB,GAAnB,mBAAmB,KAAnB,mBAAmB,QAE9B"}