diff --git a/.changeset/sour-turkeys-roll.md b/.changeset/sour-turkeys-roll.md
new file mode 100644
index 00000000000..dd4bd54a260
--- /dev/null
+++ b/.changeset/sour-turkeys-roll.md
@@ -0,0 +1,5 @@
+---
+'@finos/legend-query-builder': patch
+---
+
+Add milestoning setup in Query Option
diff --git a/.changeset/stupid-panthers-search.md b/.changeset/stupid-panthers-search.md
new file mode 100644
index 00000000000..21429dd3eca
--- /dev/null
+++ b/.changeset/stupid-panthers-search.md
@@ -0,0 +1,3 @@
+---
+'@finos/legend-application-query-bootstrap': patch
+---
diff --git a/packages/legend-application-query-bootstrap/style/index.scss b/packages/legend-application-query-bootstrap/style/index.scss
index cff822ee84d..3bbc8b230b5 100644
--- a/packages/legend-application-query-bootstrap/style/index.scss
+++ b/packages/legend-application-query-bootstrap/style/index.scss
@@ -1335,6 +1335,10 @@
color: var(--color-legacylight-light-dark-grey-200);
}
+ .query-builder__projection__result-modifier-prompt__divider {
+ color: var(--color-legacylight-light-dark-grey-200);
+ }
+
.query-builder-property-expression-badge__content {
color: var(--color-legacylight-dark-grey-200);
}
@@ -1840,4 +1844,15 @@
}
}
}
+
+ .query-builder__projection__modal {
+ ::-webkit-scrollbar-thumb {
+ height: 5rem;
+ background: var(--color-legacylight-light-grey-300);
+ outline-offset: -0.2rem;
+ border-radius: 0.4rem;
+ outline-color: var(--color-legacylight-light-grey-100);
+ border-color: var(--color-legacylight-light-grey-100);
+ }
+ }
}
diff --git a/packages/legend-query-builder/src/components/QueryBuilderSideBar.tsx b/packages/legend-query-builder/src/components/QueryBuilderSideBar.tsx
index f213fd2931d..fd0784683d7 100644
--- a/packages/legend-query-builder/src/components/QueryBuilderSideBar.tsx
+++ b/packages/legend-query-builder/src/components/QueryBuilderSideBar.tsx
@@ -47,7 +47,6 @@ import {
getPackageableElementOptionFormatter,
type PackageableElementOption,
} from '@finos/legend-lego/graph-editor';
-import { MilestoningParametersEditor } from './explorer/QueryBuilderMilestoningEditor.js';
import type { QueryBuilder_LegendApplicationPlugin_Extension } from '../stores/QueryBuilder_LegendApplicationPlugin_Extension.js';
export const getParameterValue = (
@@ -120,7 +119,6 @@ export const QueryBuilderClassSelector = observer(
noMatchMessage?: string | undefined;
}) => {
const { queryBuilderState, classes, onClassChange, noMatchMessage } = props;
- const milestoningState = queryBuilderState.milestoningState;
const applicationStore = useApplicationStore();
// class
@@ -151,10 +149,6 @@ export const QueryBuilderClassSelector = observer(
onClassChange?.(val.value);
};
- // milestoning
- const showMilestoningEditor = (): void =>
- milestoningState.setShowMilestoningEditor(true);
-
return (
@@ -192,22 +186,6 @@ export const QueryBuilderClassSelector = observer(
.TEMPORARY__isLightColorThemeEnabled,
})}
/>
- {queryBuilderState.isQuerySupported && (
-
- )}
- {milestoningState.isMilestonedQuery && (
-
- )}
);
diff --git a/packages/legend-query-builder/src/components/__tests__/QueryBuilderFetchStructure.test.tsx b/packages/legend-query-builder/src/components/__tests__/QueryBuilderFetchStructure.test.tsx
index 388b59c8b7e..bf68d767075 100644
--- a/packages/legend-query-builder/src/components/__tests__/QueryBuilderFetchStructure.test.tsx
+++ b/packages/legend-query-builder/src/components/__tests__/QueryBuilderFetchStructure.test.tsx
@@ -270,9 +270,7 @@ test(
const queryBuilder = await waitFor(() =>
renderResult.getByTestId(QUERY_BUILDER_TEST_ID.QUERY_BUILDER),
);
- fireEvent.click(
- getByTitle(queryBuilder, 'Configure result set modifiers...'),
- );
+ fireEvent.click(getByTitle(queryBuilder, 'Configure Query Options...'));
const modal = await waitFor(() => renderResult.getByRole('dialog'));
await waitFor(() => fireEvent.click(getByText(modal, 'Add Value')));
@@ -315,7 +313,7 @@ test(
fireEvent.click(getByTitle(queryBuilder, 'Clear all projection columns'));
const closeModal = await waitFor(() => renderResult.getByRole('dialog'));
fireEvent.click(getByText(closeModal, 'Proceed'));
- await waitFor(() => renderResult.getByText('Query Options'));
+ await waitFor(() => renderResult.getByText('Set Query Options'));
const queryBuilderResultModifierPrompt = await waitFor(() =>
renderResult.getByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_TDS_RESULT_MODIFIER_PROMPT,
diff --git a/packages/legend-query-builder/src/components/__tests__/QueryBuilderMilestoning.test.tsx b/packages/legend-query-builder/src/components/__tests__/QueryBuilderMilestoning.test.tsx
index 5c2f1c71bf9..7b9673cb208 100644
--- a/packages/legend-query-builder/src/components/__tests__/QueryBuilderMilestoning.test.tsx
+++ b/packages/legend-query-builder/src/components/__tests__/QueryBuilderMilestoning.test.tsx
@@ -56,6 +56,7 @@ import type { Entity } from '@finos/legend-storage';
import { TEST__setUpQueryBuilder } from '../__test-utils__/QueryBuilderComponentTestUtils.js';
import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
import { TEST_DATA__ModelCoverageAnalysisResult_Milestoning } from '../../stores/__tests__/TEST_DATA__ModelCoverageAnalysisResult.js';
+import { getParameterNameInput } from './QueryBuilderParametersPanel.test.js';
type QueryComparisonTestCase = [
string,
@@ -465,6 +466,140 @@ test(
},
);
+test(
+ integrationTest(
+ 'Query builder result modifier panel displays milestoning dates',
+ ),
+ async () => {
+ const { renderResult, queryBuilderState } = await TEST__setUpQueryBuilder(
+ TEST_MilestoningModel,
+ stub_RawLambda(),
+ 'my::map',
+ 'my::runtime',
+ TEST_DATA__ModelCoverageAnalysisResult_Milestoning,
+ );
+ const _personClass =
+ queryBuilderState.graphManagerState.graph.getClass('my::Person');
+ await act(async () => {
+ queryBuilderState.changeClass(_personClass);
+ });
+ const queryBuilderSetup = await waitFor(() =>
+ renderResult.getByTestId(QUERY_BUILDER_TEST_ID.QUERY_BUILDER_SETUP),
+ );
+ await waitFor(() => getAllByText(queryBuilderSetup, 'Person'));
+
+ const resultModifierPromptPanel = await waitFor(() =>
+ renderResult.getByTestId(
+ QUERY_BUILDER_TEST_ID.QUERY_BUILDER_TDS_RESULT_MODIFIER_PROMPT,
+ ),
+ );
+ await waitFor(() =>
+ getAllByText(resultModifierPromptPanel, 'Business Date'),
+ );
+ await waitFor(() =>
+ getAllByText(resultModifierPromptPanel, 'businessDate'),
+ );
+
+ const queryOptionsButton = await waitFor(() =>
+ renderResult.getByRole('button', { name: 'Query Options' }),
+ );
+ fireEvent.click(queryOptionsButton);
+ const allVersionsToggle = await renderResult.findByText(
+ 'Query All Milestoned Versions of the Root Class',
+ );
+ fireEvent.click(allVersionsToggle);
+ const applyButton = (await renderResult.findByRole('button', {
+ name: 'Apply',
+ })) as HTMLButtonElement;
+ await waitFor(() => fireEvent.click(applyButton));
+ await waitFor(() =>
+ getAllByText(resultModifierPromptPanel, 'All Versions'),
+ );
+ await waitFor(() => getAllByText(resultModifierPromptPanel, 'Yes'));
+ fireEvent.click(queryOptionsButton);
+ const allVersionInRangeToggle = await renderResult.findByText(
+ 'Optionally apply a date range to get All Versions for',
+ );
+ fireEvent.click(allVersionInRangeToggle);
+ fireEvent.click(renderResult.getByRole('button', { name: 'Apply' }));
+ await waitFor(() =>
+ getAllByText(resultModifierPromptPanel, '(startDate - endDate)'),
+ );
+ fireEvent.click(queryOptionsButton);
+ fireEvent.click(allVersionInRangeToggle);
+ const cancelButton = (await renderResult.findByRole('button', {
+ name: 'Cancel',
+ })) as HTMLButtonElement;
+ fireEvent.click(cancelButton);
+ await waitFor(() =>
+ getAllByText(resultModifierPromptPanel, '(startDate - endDate)'),
+ );
+ },
+);
+
+test(
+ integrationTest(
+ 'Query builder result modifier panel displays correct milestoning names after renaming milestoning parameters',
+ ),
+ async () => {
+ const { renderResult, queryBuilderState } = await TEST__setUpQueryBuilder(
+ TEST_MilestoningModel,
+ stub_RawLambda(),
+ 'my::map',
+ 'my::runtime',
+ TEST_DATA__ModelCoverageAnalysisResult_Milestoning,
+ );
+ const _personClass =
+ queryBuilderState.graphManagerState.graph.getClass('my::Person');
+ await act(async () => {
+ queryBuilderState.changeClass(_personClass);
+ });
+ const queryBuilderSetup = await waitFor(() =>
+ renderResult.getByTestId(QUERY_BUILDER_TEST_ID.QUERY_BUILDER_SETUP),
+ );
+ await waitFor(() => getAllByText(queryBuilderSetup, 'Person'));
+
+ const parameterPanel = await waitFor(() =>
+ renderResult.getByTestId(QUERY_BUILDER_TEST_ID.QUERY_BUILDER_PARAMETERS),
+ );
+
+ const resultModifierPromptPanel = await waitFor(() =>
+ renderResult.getByTestId(
+ QUERY_BUILDER_TEST_ID.QUERY_BUILDER_TDS_RESULT_MODIFIER_PROMPT,
+ ),
+ );
+ await waitFor(() =>
+ getAllByText(resultModifierPromptPanel, 'Business Date'),
+ );
+ await waitFor(() =>
+ getAllByText(resultModifierPromptPanel, 'businessDate'),
+ );
+ fireEvent.click(getByText(parameterPanel, 'businessDate'));
+ const parameterNameInput = getParameterNameInput(renderResult);
+ fireEvent.change(parameterNameInput, {
+ target: { value: 'businessDateRenamed' },
+ });
+ const updateButton = (await renderResult.findByRole('button', {
+ name: 'Update',
+ })) as HTMLButtonElement;
+ fireEvent.click(updateButton);
+ await waitFor(() =>
+ getAllByText(resultModifierPromptPanel, 'businessDateRenamed'),
+ );
+ const queryOptionsButton = await waitFor(() =>
+ renderResult.getByRole('button', { name: 'Query Options' }),
+ );
+ fireEvent.click(queryOptionsButton);
+ const cancelButton = (await renderResult.findByRole('button', {
+ name: 'Cancel',
+ })) as HTMLButtonElement;
+ fireEvent.click(cancelButton);
+ await waitFor(() =>
+ getAllByText(resultModifierPromptPanel, 'businessDateRenamed'),
+ );
+ },
+);
+
type QueryGetAllVersionsTestCase = [
string,
{
@@ -571,14 +706,23 @@ describe(
);
});
- renderResult.getByTitle('Edit Milestoning Parameters');
- fireEvent.click(renderResult.getByTitle('Edit Milestoning Parameters'));
+ const queryOptionsButton = await waitFor(() =>
+ renderResult.getByRole('button', { name: 'Query Options' }),
+ );
+ fireEvent.click(queryOptionsButton);
const dialog = await waitFor(() => renderResult.getByRole('dialog'));
fireEvent.click(
getByText(dialog, 'Query All Milestoned Versions of the Root Class'),
);
+
+ const applyButton = (await renderResult.findByRole('button', {
+ name: 'Apply',
+ })) as HTMLButtonElement;
+
+ await waitFor(() => fireEvent.click(applyButton));
+
const receivedOutput = queryBuilderState.buildQuery();
// Compare input JSON and output JSON for building a query
@@ -666,11 +810,11 @@ describe(
);
});
- renderResult.getByTitle('Edit Milestoning Parameters');
- fireEvent.click(renderResult.getByTitle('Edit Milestoning Parameters'));
-
+ const queryOptionsButton = await waitFor(() =>
+ renderResult.getByRole('button', { name: 'Query Options' }),
+ );
+ fireEvent.click(queryOptionsButton);
const dialog = await waitFor(() => renderResult.getByRole('dialog'));
-
// Check if we are setting start date and end date when allVersionsInRange() is selected
fireEvent.click(
getByText(
@@ -678,6 +822,7 @@ describe(
'Optionally apply a date range to get All Versions for',
),
);
+
expect(getAllByText(dialog, 'startDate').length).toBe(2);
expect(getAllByText(dialog, 'endDate').length).toBe(2);
diff --git a/packages/legend-query-builder/src/components/__tests__/QueryBuilderParametersPanel.test.tsx b/packages/legend-query-builder/src/components/__tests__/QueryBuilderParametersPanel.test.tsx
index 43e2afc0ce5..d7b179410eb 100644
--- a/packages/legend-query-builder/src/components/__tests__/QueryBuilderParametersPanel.test.tsx
+++ b/packages/legend-query-builder/src/components/__tests__/QueryBuilderParametersPanel.test.tsx
@@ -51,7 +51,9 @@ import {
} from '@finos/legend-lego/code-editor/test';
import { guaranteeNonNullable } from '@finos/legend-shared';
-const getParameterNameInput = (renderResult: RenderResult): HTMLInputElement =>
+export const getParameterNameInput = (
+ renderResult: RenderResult,
+): HTMLInputElement =>
getByRole(
guaranteeNonNullable(
renderResult.getByText('Parameter Name').parentElement,
diff --git a/packages/legend-query-builder/src/components/__tests__/QueryBuilderResultModifierPanel.test.tsx b/packages/legend-query-builder/src/components/__tests__/QueryBuilderResultModifierPanel.test.tsx
index 804f45be11b..f033b73253a 100644
--- a/packages/legend-query-builder/src/components/__tests__/QueryBuilderResultModifierPanel.test.tsx
+++ b/packages/legend-query-builder/src/components/__tests__/QueryBuilderResultModifierPanel.test.tsx
@@ -91,7 +91,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
@@ -144,7 +145,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
@@ -193,7 +195,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
@@ -255,7 +258,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
@@ -292,7 +296,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
@@ -347,7 +352,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
@@ -383,7 +389,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
@@ -425,7 +432,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
@@ -469,7 +477,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
@@ -524,7 +533,8 @@ describe('QueryBuilderResultModifierPanel', () => {
),
async () => {
// Open Query Options panel
- const queryOptionsButton = await renderResult.findByText('Query Options');
+ const queryOptionsButton =
+ await renderResult.findByText('Set Query Options');
fireEvent.click(queryOptionsButton);
const resultModifierPanel = await renderResult.findByTestId(
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_RESULT_MODIFIER_PANEL,
diff --git a/packages/legend-query-builder/src/components/__tests__/QueryBuilderWatermark.test.tsx b/packages/legend-query-builder/src/components/__tests__/QueryBuilderWatermark.test.tsx
index ab2c66f8c3b..a6ba4ebda1a 100644
--- a/packages/legend-query-builder/src/components/__tests__/QueryBuilderWatermark.test.tsx
+++ b/packages/legend-query-builder/src/components/__tests__/QueryBuilderWatermark.test.tsx
@@ -47,7 +47,7 @@ test(
// Open Query Options modal
const queryOptionsButton = await waitFor(() =>
- renderResult.getByRole('button', { name: 'Query Options' }),
+ renderResult.getByRole('button', { name: 'Set Query Options' }),
);
fireEvent.click(queryOptionsButton);
fireEvent.click(
@@ -103,7 +103,7 @@ test(
// Open Query Options modal, enable and save watermark
const queryOptionsButton = await waitFor(() =>
- renderResult.getByRole('button', { name: 'Query Options' }),
+ renderResult.getByRole('button', { name: 'Set Query Options' }),
);
fireEvent.click(queryOptionsButton);
fireEvent.click(
@@ -183,7 +183,7 @@ test(
// Open watermark modal
const queryOptionsButton = await waitFor(() =>
- renderResult.getByRole('button', { name: 'Query Options' }),
+ renderResult.getByRole('button', { name: 'Set Query Options' }),
);
fireEvent.click(queryOptionsButton);
await waitFor(() => renderResult.getByText('Watermark'));
diff --git a/packages/legend-query-builder/src/components/explorer/QueryBuilderMilestoningEditor.tsx b/packages/legend-query-builder/src/components/explorer/QueryBuilderMilestoningEditor.tsx
index f69e6989c5e..6dba90f3cd7 100644
--- a/packages/legend-query-builder/src/components/explorer/QueryBuilderMilestoningEditor.tsx
+++ b/packages/legend-query-builder/src/components/explorer/QueryBuilderMilestoningEditor.tsx
@@ -19,7 +19,6 @@ import type { QueryBuilderState } from '../../stores/QueryBuilderState.js';
import { useCallback } from 'react';
import {
type ValueSpecification,
- type VariableExpression,
GenericType,
GenericTypeExplicitReference,
observe_PrimitiveInstanceValue,
@@ -27,19 +26,8 @@ import {
PRIMITIVE_TYPE,
PrimitiveType,
} from '@finos/legend-graph';
-import { guaranteeNonNullable } from '@finos/legend-shared';
import { useDrop } from 'react-dnd';
-import {
- Dialog,
- Modal,
- ModalBody,
- ModalFooter,
- ModalFooterButton,
- ModalHeader,
- PanelEntryDropZonePlaceholder,
- PanelFormBooleanField,
- PanelFormSection,
-} from '@finos/legend-art';
+import { PanelEntryDropZonePlaceholder } from '@finos/legend-art';
import { generateDefaultValueForPrimitiveType } from '../../stores/QueryBuilderValueSpecificationHelper.js';
import {
BasicValueSpecificationEditor,
@@ -47,9 +35,8 @@ import {
QUERY_BUILDER_VARIABLE_DND_TYPE,
} from '../shared/BasicValueSpecificationEditor.js';
import { instanceValue_setValues } from '../../stores/shared/ValueSpecificationModifierHelper.js';
-import { VariableSelector } from '../shared/QueryBuilderVariableSelector.js';
-const MilestoningParameterEditor = observer(
+export const MilestoningParameterEditor = observer(
(props: {
queryBuilderState: QueryBuilderState;
parameter: ValueSpecification;
@@ -125,240 +112,3 @@ const MilestoningParameterEditor = observer(
);
},
);
-
-const BiTemporalMilestoningEditor = observer(
- (props: { queryBuilderState: QueryBuilderState }) => {
- const { queryBuilderState } = props;
- return (
- <>
-
-
- Processing Date
-
-
- queryBuilderState.milestoningState.setProcessingDate(val)
- }
- />
-
-
-
- Business Date
-
-
- queryBuilderState.milestoningState.setBusinessDate(val)
- }
- />
-
- >
- );
- },
-);
-
-const BusinessTemporalMilestoningEditor = observer(
- (props: { queryBuilderState: QueryBuilderState }) => {
- const { queryBuilderState } = props;
- return (
-
-
- Business Date
-
-
- queryBuilderState.milestoningState.setBusinessDate(val)
- }
- />
-
- );
- },
-);
-
-const ProcessingTemporalMilestoningEditor = observer(
- (props: { queryBuilderState: QueryBuilderState }) => {
- const { queryBuilderState } = props;
- return (
-
-
- Processing Date
-
-
- queryBuilderState.milestoningState.setProcessingDate(val)
- }
- />
-
- );
- },
-);
-
-const TemporalMilestoningEditor: React.FC<{
- queryBuilderState: QueryBuilderState;
-}> = (props) => {
- const { queryBuilderState } = props;
-
- if (
- queryBuilderState.milestoningState.processingDate &&
- queryBuilderState.milestoningState.businessDate
- ) {
- return (
-
- );
- } else if (queryBuilderState.milestoningState.businessDate) {
- return (
-
- );
- } else if (queryBuilderState.milestoningState.processingDate) {
- return (
-
- );
- } else {
- return null;
- }
-};
-
-const AllVersionsInRangelMilestoningParametersEditor = observer(
- (props: { queryBuilderState: QueryBuilderState }) => {
- const { queryBuilderState } = props;
-
- return (
-
-
-
- Start Date
-
-
- queryBuilderState.milestoningState.setStartDate(val)
- }
- />
-
-
-
- End Date
-
-
- queryBuilderState.milestoningState.setEndDate(val)
- }
- />
-
-
- );
- },
-);
-
-export const MilestoningParametersEditor = observer(
- (props: { queryBuilderState: QueryBuilderState }) => {
- const { queryBuilderState } = props;
- const applicationStore = queryBuilderState.applicationStore;
- const milestoningState = queryBuilderState.milestoningState;
- const close = (): void => milestoningState.setShowMilestoningEditor(false);
- const isCompatibleMilestoningParameter = (
- variable: VariableExpression,
- ): boolean =>
- variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.STRICTDATE ||
- variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.LATESTDATE ||
- variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.DATE ||
- variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.DATETIME;
-
- return (
-
- );
- },
-);
diff --git a/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx b/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx
index 99e87884edf..1b6acf33ee0 100644
--- a/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx
+++ b/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx
@@ -33,6 +33,8 @@ import {
PanelFormSection,
ArrowUpIcon,
ArrowDownIcon,
+ PanelFormBooleanField,
+ PanelFormListItems,
} from '@finos/legend-art';
import { SortColumnState } from '../../stores/fetch-structure/tds/QueryResultSetModifierState.js';
import {
@@ -41,21 +43,36 @@ import {
deepClone,
deleteEntry,
guaranteeNonNullable,
+ isNonNullable,
} from '@finos/legend-shared';
import { useApplicationStore } from '@finos/legend-application';
import type { QueryBuilderTDSState } from '../../stores/fetch-structure/tds/QueryBuilderTDSState.js';
import type { QueryBuilderTDSColumnState } from '../../stores/fetch-structure/tds/QueryBuilderTDSColumnState.js';
-import { COLUMN_SORT_TYPE } from '../../graph/QueryBuilderMetaModelConst.js';
+import {
+ COLUMN_SORT_TYPE,
+ QUERY_BUILDER_SUPPORTED_GET_ALL_FUNCTIONS,
+} from '../../graph/QueryBuilderMetaModelConst.js';
import { useCallback, useEffect, useState } from 'react';
import type { QueryBuilderProjectionColumnState } from '../../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
-import { VariableSelector } from '../shared/QueryBuilderVariableSelector.js';
+import {
+ VariableSelector,
+ VariableViewer,
+} from '../shared/QueryBuilderVariableSelector.js';
import {
type ValueSpecification,
- type VariableExpression,
+ VariableExpression,
PrimitiveType,
Multiplicity,
areMultiplicitiesEqual,
+ PRIMITIVE_TYPE,
+ MILESTONING_START_DATE_PARAMETER_NAME,
+ GenericType,
+ GenericTypeExplicitReference,
+ MILESTONING_END_DATE_PARAMETER_NAME,
+ getMilestoneTemporalStereotype,
+ BUSINESS_DATE_MILESTONING_PROPERTY_NAME,
+ PROCESSING_DATE_MILESTONING_PROPERTY_NAME,
} from '@finos/legend-graph';
import {
BasicValueSpecificationEditor,
@@ -63,6 +80,9 @@ import {
type QueryBuilderVariableDragSource,
} from '../shared/BasicValueSpecificationEditor.js';
import { useDrop } from 'react-dnd';
+import { MilestoningParameterEditor } from '../explorer/QueryBuilderMilestoningEditor.js';
+import { QueryBuilderSimpleConstantExpressionState } from '../../stores/QueryBuilderConstantsState.js';
+import { LambdaParameterState } from '../../stores/shared/LambdaParameterState.js';
const ColumnSortEditor = observer(
(props: {
@@ -275,21 +295,6 @@ export const QueryResultModifierModal = observer(
stateSlice,
]);
- // Handle user actions
- const closeModal = (): void => resultSetModifierState.setShowModal(false);
- const applyChanges = (): void => {
- resultSetModifierState.setSortColumns(sortColumns);
- resultSetModifierState.setDistinct(distinct);
- resultSetModifierState.setLimit(limitResults);
- if (slice[0] !== undefined && slice[1] !== undefined) {
- resultSetModifierState.setSlice([slice[0], slice[1]]);
- } else {
- resultSetModifierState.setSlice(undefined);
- }
- resultSetModifierState.setShowModal(false);
- watermarkState.setValue(watermarkValue);
- };
-
const handleLimitResultsChange: React.ChangeEventHandler<
HTMLInputElement
> = (event) => {
@@ -380,6 +385,273 @@ export const QueryResultModifierModal = observer(
[handleDrop],
);
+ //milestoning config
+ const isCompatibleMilestoningParameter = (
+ variable: VariableExpression,
+ ): boolean =>
+ variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.STRICTDATE ||
+ variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.LATESTDATE ||
+ variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.DATE ||
+ variable.genericType?.value.rawType.name === PRIMITIVE_TYPE.DATETIME;
+
+ const milestoningState = tdsState.queryBuilderState.milestoningState;
+ const [parameterStates, setParameterStates] = useState(
+ milestoningState.queryBuilderState.parametersState.parameterStates,
+ );
+ const filteredParameterStates = parameterStates.filter((p) =>
+ isCompatibleMilestoningParameter(p.parameter),
+ );
+ const filteredConstantState =
+ milestoningState.queryBuilderState.constantState.constants.filter((c) =>
+ isCompatibleMilestoningParameter(c.variable),
+ );
+
+ const [isAllVersionsEnabled, setIsAllVersionsEnabled] = useState(
+ milestoningState.isAllVersionsEnabled,
+ );
+ const [isAllVersionsInRangeEnabled, setIsAllVersionsInRangeEnabled] =
+ useState(milestoningState.isAllVersionsInRangeEnabled);
+ const [businessDate, setBusinessDate] = useState(
+ milestoningState.businessDate,
+ );
+ const [processingDate, setProcessingDate] = useState(
+ milestoningState.processingDate,
+ );
+ const [startDate, setStartDate] = useState(milestoningState.startDate);
+ const [endDate, setEndDate] = useState(milestoningState.endDate);
+
+ const shouldFilterMilestoningParamIfNotUsed = (
+ param: ValueSpecification | undefined,
+ resetParameter: (val: ValueSpecification | undefined) => void,
+ ): ((lambdaParamState: LambdaParameterState) => boolean) => {
+ if (param && param instanceof VariableExpression) {
+ if (
+ !milestoningState.queryBuilderState.isVariableUsed(param, {
+ exculdeMilestoningState: true,
+ })
+ ) {
+ resetParameter(undefined);
+ return (lambdaParamState: LambdaParameterState) =>
+ lambdaParamState.parameter.name !== param.name;
+ }
+ }
+ return (lambdaParamState: LambdaParameterState) => true;
+ };
+
+ const setAllVersions = (value: boolean | undefined): void => {
+ if (value) {
+ //clean all unused milestoning parameters e.g. businessDate, ..., endDate.
+ setParameterStates([
+ ...parameterStates.filter(
+ (ps) =>
+ shouldFilterMilestoningParamIfNotUsed(
+ businessDate,
+ setBusinessDate,
+ )(ps) &&
+ shouldFilterMilestoningParamIfNotUsed(
+ processingDate,
+ setProcessingDate,
+ )(ps) &&
+ shouldFilterMilestoningParamIfNotUsed(
+ startDate,
+ setStartDate,
+ )(ps) &&
+ shouldFilterMilestoningParamIfNotUsed(endDate, setEndDate)(ps),
+ ),
+ ]);
+ } else {
+ //get or initialize getAll() parameters
+ setIsAllVersionsInRangeEnabled(false);
+ let newParamStates: LambdaParameterState[] = [];
+ if (
+ (!businessDate || !processingDate) &&
+ milestoningState.queryBuilderState.class
+ ) {
+ const stereotype = getMilestoneTemporalStereotype(
+ milestoningState.queryBuilderState.class,
+ milestoningState.queryBuilderState.graphManagerState.graph,
+ );
+ if (stereotype) {
+ const existingParamStates = parameterStates.map(
+ (ps) => ps.variableName,
+ );
+ newParamStates = milestoningState
+ .getMilestoningImplementation(stereotype)
+ .buildParameterStatesFromMilestoningParameters()
+ .filter((ps) => !existingParamStates.includes(ps.parameter.name));
+ }
+ }
+ const allParamStates = [...newParamStates, ...parameterStates].filter(
+ (ps) =>
+ shouldFilterMilestoningParamIfNotUsed(
+ startDate,
+ setStartDate,
+ )(ps) &&
+ shouldFilterMilestoningParamIfNotUsed(endDate, setEndDate)(ps),
+ );
+ setParameterStates(allParamStates);
+ if (!businessDate) {
+ setBusinessDate(
+ allParamStates.find(
+ (ps) =>
+ ps.variableName === BUSINESS_DATE_MILESTONING_PROPERTY_NAME,
+ )?.parameter,
+ );
+ }
+ if (!processingDate) {
+ setProcessingDate(
+ allParamStates.find(
+ (ps) =>
+ ps.variableName === PROCESSING_DATE_MILESTONING_PROPERTY_NAME,
+ )?.parameter,
+ );
+ }
+ }
+ setIsAllVersionsEnabled(Boolean(value));
+ };
+
+ const buildAllVersionsInRangeParameters = (): void => {
+ let startDateParameterState;
+ let endDateParameterState;
+ if (!(startDate && startDate instanceof VariableExpression)) {
+ const startDateVar = new VariableExpression(
+ MILESTONING_START_DATE_PARAMETER_NAME,
+ Multiplicity.ONE,
+ GenericTypeExplicitReference.create(
+ new GenericType(PrimitiveType.DATE),
+ ),
+ );
+ setStartDate(startDateVar);
+ startDateParameterState = new LambdaParameterState(
+ startDateVar,
+ milestoningState.queryBuilderState.observerContext,
+ milestoningState.queryBuilderState.graphManagerState.graph,
+ );
+ startDateParameterState.mockParameterValue();
+ }
+ if (!(endDate && endDate instanceof VariableExpression)) {
+ const endDateVar = new VariableExpression(
+ MILESTONING_END_DATE_PARAMETER_NAME,
+ Multiplicity.ONE,
+ GenericTypeExplicitReference.create(
+ new GenericType(PrimitiveType.DATE),
+ ),
+ );
+ setEndDate(endDateVar);
+ endDateParameterState = new LambdaParameterState(
+ endDateVar,
+ milestoningState.queryBuilderState.observerContext,
+ milestoningState.queryBuilderState.graphManagerState.graph,
+ );
+ endDateParameterState.mockParameterValue();
+ }
+ setParameterStates([
+ ...parameterStates.filter(
+ (ps) =>
+ shouldFilterMilestoningParamIfNotUsed(
+ businessDate,
+ setBusinessDate,
+ )(ps) &&
+ shouldFilterMilestoningParamIfNotUsed(
+ processingDate,
+ setProcessingDate,
+ )(ps),
+ ),
+ ...[startDateParameterState, endDateParameterState].filter(
+ isNonNullable,
+ ),
+ ]);
+ };
+
+ const setAllVersionsInRange = (value: boolean | undefined): void => {
+ if (value) {
+ buildAllVersionsInRangeParameters();
+ } else {
+ setAllVersions(true);
+ }
+ setIsAllVersionsInRangeEnabled(Boolean(value));
+ };
+
+ const resetMilestoningConfig = (): void => {
+ setIsAllVersionsEnabled(milestoningState.isAllVersionsEnabled);
+ setIsAllVersionsInRangeEnabled(
+ milestoningState.isAllVersionsInRangeEnabled,
+ );
+ setEndDate(milestoningState.endDate);
+ setBusinessDate(milestoningState.businessDate);
+ setProcessingDate(milestoningState.processingDate);
+ setParameterStates(
+ milestoningState.queryBuilderState.parametersState.parameterStates,
+ );
+ };
+
+ // Handle user actions
+ const closeModal = (): void => {
+ resetMilestoningConfig();
+ resultSetModifierState.setShowModal(false);
+ };
+
+ const applyChanges = (): void => {
+ resultSetModifierState.setSortColumns(sortColumns);
+ resultSetModifierState.setDistinct(distinct);
+ resultSetModifierState.setLimit(limitResults);
+ if (slice[0] !== undefined && slice[1] !== undefined) {
+ resultSetModifierState.setSlice([slice[0], slice[1]]);
+ } else {
+ resultSetModifierState.setSlice(undefined);
+ }
+ resultSetModifierState.setShowModal(false);
+ watermarkState.setValue(watermarkValue);
+ milestoningState.queryBuilderState.parametersState.setParameters(
+ parameterStates,
+ );
+ if (isAllVersionsInRangeEnabled) {
+ milestoningState.setStartDate(startDate);
+ milestoningState.setEndDate(endDate);
+ milestoningState.clearGetAllParameters();
+ milestoningState.queryBuilderState.setGetAllFunction(
+ QUERY_BUILDER_SUPPORTED_GET_ALL_FUNCTIONS.GET_ALL_VERSIONS_IN_RANGE,
+ );
+ } else if (isAllVersionsEnabled) {
+ milestoningState.clearGetAllParameters();
+ milestoningState.queryBuilderState.setGetAllFunction(
+ QUERY_BUILDER_SUPPORTED_GET_ALL_FUNCTIONS.GET_ALL_VERSIONS,
+ );
+ } else if (
+ tdsState.queryBuilderState.milestoningState.isMilestonedQuery
+ ) {
+ milestoningState.clearAllVersionsInRangeParameters();
+ milestoningState.setBusinessDate(businessDate);
+ milestoningState.setProcessingDate(processingDate);
+ milestoningState.queryBuilderState.setGetAllFunction(
+ QUERY_BUILDER_SUPPORTED_GET_ALL_FUNCTIONS.GET_ALL,
+ );
+ }
+ milestoningState.updateQueryBuilderState();
+ };
+
+ useEffect(() => {
+ setIsAllVersionsEnabled(milestoningState.isAllVersionsEnabled);
+ setIsAllVersionsInRangeEnabled(
+ milestoningState.isAllVersionsInRangeEnabled,
+ );
+ setEndDate(milestoningState.endDate);
+ setBusinessDate(milestoningState.businessDate);
+ setProcessingDate(milestoningState.processingDate);
+ setParameterStates(
+ milestoningState.queryBuilderState.parametersState.parameterStates,
+ );
+ }, [
+ milestoningState.isAllVersionsEnabled,
+ milestoningState.isAllVersionsInRangeEnabled,
+ milestoningState.queryBuilderState.parametersState.parameterStates,
+ milestoningState.businessDate,
+ milestoningState.processingDate,
+ milestoningState.startDate,
+ milestoningState.endDate,
+ milestoningState.queryBuilderState.class,
+ ]);
+
return (