Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/full-donuts-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@finos/legend-lego': patch
---

DataGrid - allows users to make their own onGridReady callback
5 changes: 5 additions & 0 deletions .changeset/goofy-lions-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@finos/legend-extension-dsl-data-product': patch
---

Fixed link copying, direction on loading, and added APG anchors
Original file line number Diff line number Diff line change
Expand Up @@ -498,13 +498,27 @@ const AccessPointTable = observer(
<DataGrid
rowData={accessPointState.relationType?.columns ?? []}
columnDefs={relationColumnDefs}
onGridReady={(params) => setGridApi(params.api)}
domLayout={
(accessPointState.relationType?.columns.length ?? 0) >
MAX_GRID_AUTO_HEIGHT_ROWS
? 'normal'
: 'autoHeight'
}
onGridReady={(params) => {
setGridApi(params.api);
if (!accessPointState.relationType?.columns.length) {
accessPointState.apgState.dataProductViewerState.layoutState.markGridAsRendered();
}
}}
onFirstDataRendered={() => {
if (
accessPointState.relationType?.columns.length !==
undefined &&
accessPointState.relationType.columns.length > 0
) {
accessPointState.apgState.dataProductViewerState.layoutState.markGridAsRendered();
}
}}
/>
</Box>
) : (
Expand Down Expand Up @@ -674,6 +688,19 @@ export const DataProductAccessPointGroupViewer = observer(
const [isEntitledButtonGroupMenuOpen, setIsEntitledButtonGroupMenuOpen] =
useState(false);
const requestAccessButtonGroupRef = useRef<HTMLDivElement | null>(null);
const sectionRef = useRef<HTMLDivElement>(null);
const anchor = generateAnchorForSection(`apg-${apgState.apg.id}`);

useEffect(() => {
if (sectionRef.current) {
apgState.dataProductViewerState.layoutState.setWikiPageAnchor(
anchor,
sectionRef.current,
);
}
return () =>
apgState.dataProductViewerState.layoutState.unsetWikiPageAnchor(anchor);
}, [apgState, anchor]);

const entitlementsDataContractViewerState = useMemo(() => {
return dataAccessState?.contractViewerContractAndSubscription &&
Expand Down Expand Up @@ -863,7 +890,10 @@ export const DataProductAccessPointGroupViewer = observer(
};

return (
<div className="data-product__viewer__access-group__item">
<div
ref={sectionRef}
className="data-product__viewer__access-group__item"
>
<div className="data-product__viewer__access-group__item__header">
<div className="data-product__viewer__access-group__item__header-main">
<div className="data-product__viewer__access-group__item__header__title">
Expand All @@ -875,6 +905,10 @@ export const DataProductAccessPointGroupViewer = observer(
<button
className="data-product__viewer__access-group__item__header__anchor"
tabIndex={-1}
onClick={() => {
apgState.dataProductViewerState.changeZone(anchor, true);
apgState.dataProductViewerState.copyLinkToClipboard(anchor);
}}
>
<AnchorLinkIcon />
</button>
Expand Down Expand Up @@ -1004,7 +1038,10 @@ export const DataProducteDataAccess = observer(
<button
className="data-product__viewer__wiki__section__header__anchor"
tabIndex={-1}
onClick={() => dataProductViewerState.changeZone(anchor, true)}
onClick={() => {
dataProductViewerState.changeZone(anchor, true);
dataProductViewerState.copyLinkToClipboard(anchor);
}}
>
<AnchorLinkIcon />
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,10 @@ export const DataProductSupportInfo = observer(
<button
className="data-product__viewer__wiki__section__header__anchor"
tabIndex={-1}
onClick={() => dataProductViewerState.changeZone(anchor, true)}
onClick={() => {
dataProductViewerState.changeZone(anchor, true);
dataProductViewerState.copyLinkToClipboard(anchor);
}}
>
<AnchorLinkIcon />
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { V1_ExternalDataProductType } from '@finos/legend-graph';
import { prettyCONSTName } from '@finos/legend-shared';
import { ModelsDocumentation } from '@finos/legend-lego/model-documentation';
import { DiagramViewer } from '@finos/legend-extension-dsl-diagram';
import { useNavigationZone } from '@finos/legend-application/browser';

export const ProductWikiPlaceholder: React.FC<{ message: string }> = (
props,
Expand Down Expand Up @@ -211,6 +212,14 @@ export const ProductWiki = observer(
| undefined;
}) => {
const { productViewerState, productDataAccessState } = props;
const navigationZone = useNavigationZone();

useEffect(() => {
productViewerState.layoutState.setWikiPageAnchorToNavigate({
anchor: navigationZone,
});
productViewerState.changeZone(navigationZone);
}, [productViewerState, navigationZone]);

useEffect(() => {
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ import type {
ProjectGAVCoordinates,
StoredFileGeneration,
} from '@finos/legend-storage';
import {
MockedMonacoEditorAPI,
MockedMonacoEditorInstance,
MockedMonacoEditorModel,
} from '@finos/legend-lego/code-editor/test';
import { BrowserRouter } from '@finos/legend-application/browser';

jest.mock('react-oidc-context', () => {
const { MOCK__reactOIDCContext } = jest.requireActual<{
Expand Down Expand Up @@ -254,12 +260,14 @@ const setupLakehouseDataProductTest = async (
await act(async () => {
await flowResult(dataProductDataAccessState?.init(undefined));
renderResult = render(
<AuthProvider>
<ProductViewer
productViewerState={dataProductViewerState}
productDataAccessState={dataProductDataAccessState}
/>
</AuthProvider>,
<BrowserRouter>
<AuthProvider>
<ProductViewer
productViewerState={dataProductViewerState}
productDataAccessState={dataProductDataAccessState}
/>
</AuthProvider>
</BrowserRouter>,
);

await new Promise((resolve) => setTimeout(resolve, 0)); // wait for async state updates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@
import { action, computed, makeObservable, observable } from 'mobx';
import { isNonNullable } from '@finos/legend-shared';
import {
DATA_PRODUCT_VIEWER_ANCHORS,
DATA_PRODUCT_DEFAULT_ANCHORS,
DATA_PRODUCT_MODELAPG_ANCHORS,
DATA_PRODUCT_VDP_ANCHORS,
generateAnchorForSection,
TERMINAL_PRODUCT_VIEWER_ANCHORS,
} from './ProductViewerNavigation.js';
import { NAVIGATION_ZONE_SEPARATOR } from '@finos/legend-application';
import type { V1_DataProduct } from '@finos/legend-graph';
import type { DataProductViewerState } from './DataProduct/DataProductViewerState.js';

export type WikiPageNavigationCommand = { anchor: string };

Expand All @@ -33,6 +38,7 @@ export abstract class BaseLayoutState {
private wikiPageAnchorIndex = new Map<string, HTMLElement>();
wikiPageNavigationCommand?: WikiPageNavigationCommand | undefined;
private wikiPageVisibleAnchors: string[] = [];
private renderedGrids = 0;
private wikiPageScrollIntersectionObserver?: IntersectionObserver | undefined;

constructor() {
Expand All @@ -41,6 +47,8 @@ export abstract class BaseLayoutState {
| 'wikiPageAnchorIndex'
| 'wikiPageVisibleAnchors'
| 'updatePageVisibleAnchors'
| 'renderedGrids'
| 'expectedGridCount'
>(this, {
currentNavigationZone: observable,
isExpandedModeEnabled: observable,
Expand All @@ -49,29 +57,42 @@ export abstract class BaseLayoutState {
frame: observable.ref,
wikiPageAnchorIndex: observable,
wikiPageNavigationCommand: observable.ref,
renderedGrids: observable,
isWikiPageFullyRendered: computed,
expectedGridCount: computed,
registerWikiPageScrollObserver: action,
setCurrentNavigationZone: action,
enableExpandedMode: action,
setFrame: action,
setTopScrollerVisible: action,
setWikiPageAnchor: action,
markGridAsRendered: action,
unsetWikiPageAnchor: action,
setWikiPageAnchorToNavigate: action,
updatePageVisibleAnchors: action,
});
}

protected abstract getValidAnchors(): string[];
protected abstract get expectedGridCount(): number;

get isWikiPageFullyRendered(): boolean {
return (
const allAnchorsPresent =
Boolean(this.frame) &&
this.getValidAnchors().every((anchor) =>
this.wikiPageAnchorIndex.has(anchor),
) &&
Array.from(this.wikiPageAnchorIndex.values()).every(isNonNullable)
);
Array.from(this.wikiPageAnchorIndex.values()).every(isNonNullable);

const areAllGridsRendered =
this.expectedGridCount === 0 ||
this.renderedGrids >= this.expectedGridCount;

return allAnchorsPresent && areAllGridsRendered;
}

markGridAsRendered(): void {
this.renderedGrids += 1;
}

setCurrentNavigationZone(val: string): void {
Expand Down Expand Up @@ -208,13 +229,50 @@ export abstract class BaseLayoutState {
}

export class DataProductLayoutState extends BaseLayoutState {
private dataProduct: V1_DataProduct;
private dataProductViewerState!: DataProductViewerState;

constructor(dataProduct: V1_DataProduct) {
super();
this.dataProduct = dataProduct;
}

get expectedGridCount(): number {
return this.dataProduct.accessPointGroups.reduce(
(total, apg) => total + apg.accessPoints.length,
0,
);
}

setViewerState(viewerState: DataProductViewerState): void {
this.dataProductViewerState = viewerState;
}

protected getValidAnchors(): string[] {
return DATA_PRODUCT_VIEWER_ANCHORS;
const anchors = [...DATA_PRODUCT_DEFAULT_ANCHORS]
.concat(
this.dataProductViewerState.isVDP ? [...DATA_PRODUCT_VDP_ANCHORS] : [],
)
.concat(
this.dataProductViewerState.getModelAccessPointGroup()
? [...DATA_PRODUCT_MODELAPG_ANCHORS]
: [],
);

const apgAnchors = this.dataProduct.accessPointGroups.map((apg) =>
generateAnchorForSection(`apg-${apg.id}`),
);

return [...anchors, ...apgAnchors];
}
}

export class TerminalProductLayoutState extends BaseLayoutState {
protected getValidAnchors(): string[] {
return TERMINAL_PRODUCT_VIEWER_ANCHORS;
}

protected get expectedGridCount(): number {
return 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,18 @@ export abstract class BaseViewerState<
this.layoutState.setCurrentNavigationZone(zone);
}
}

copyLinkToClipboard(zone: NavigationZone): void {
const url = `${window.location.origin}${window.location.pathname}#${zone}`;
this.applicationStore.clipboardService
.copyTextToClipboard(url)
.then(() =>
this.applicationStore.notificationService.notifySuccess(
'Copied to clipboard',
undefined,
2500,
),
)
.catch(this.applicationStore.alertUnhandledError);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,14 @@ export class DataProductViewerState extends BaseViewerState<
openDataCube?: (sourceData: object) => void;
},
) {
super(product, applicationStore, new DataProductLayoutState(), actions);
super(
product,
applicationStore,
new DataProductLayoutState(product),
actions,
);

this.layoutState.setViewerState(this);

makeObservable(this, {
dataProductArtifact: observable,
Expand Down Expand Up @@ -148,6 +155,14 @@ export class DataProductViewerState extends BaseViewerState<
);
}

getModelAccessPointGroup(): V1_ModelAccessPointGroup | undefined {
const modelapg = this.product.accessPointGroups.find(
(apg): apg is V1_ModelAccessPointGroup =>
apg instanceof V1_ModelAccessPointGroup,
);
return modelapg;
}

get isVDP(): boolean {
const vendorProfile = this.dataProductConfig?.vendorTaggedValue.profile;
if (!vendorProfile) {
Expand All @@ -160,13 +175,6 @@ export class DataProductViewerState extends BaseViewerState<
);
}

getModelAccessPointGroup(): V1_ModelAccessPointGroup | undefined {
return this.product.accessPointGroups.find(
(apg): apg is V1_ModelAccessPointGroup =>
apg instanceof V1_ModelAccessPointGroup,
);
}

getModelAccessPointDiagrams(): DiagramAnalysisResult[] {
const modelAPG = this.getModelAccessPointGroup();

Expand Down
Loading