import { isJsonEqual } from "@milaboratories/helpers"; import { parseJson, PlSelectionModel } from "@platforma-sdk/model"; import { CellRendererSelectorFunc, GridApi, GridOptions, ManagedGridOptionKey, ManagedGridOptions, } from "ag-grid-enterprise"; import { type Ref, shallowRef } from "vue"; import { autoSizeRowNumberColumn } from "../sources/row-number"; import { PlAgDataTableV2Row, PlTableRowIdJson, PlAgOverlayLoadingParams, PlAgOverlayNoRowsParams, } from "../types"; import PlOverlayLoading from "../PlAgOverlayLoading.vue"; import PlOverlayNoRows from "../PlAgOverlayNoRows.vue"; import { isNil } from "es-toolkit"; export function useGrid({ selection, noRowsText, loadingText, runningText, notReadyText, cellRendererSelector, }: { selection: Ref; noRowsText?: string; loadingText?: string; runningText?: string; notReadyText?: string; cellRendererSelector?: CellRendererSelectorFunc; }) { const gridApi = shallowRef | null>(null); const gridOptions = shallowRef>({ animateRows: false, suppressColumnMoveAnimation: true, cellSelection: isNil(selection.value), autoSizeStrategy: { type: "fitCellContents" }, rowSelection: selection.value ? { mode: "multiRow", selectAll: "all", groupSelects: "self", checkboxes: false, headerCheckbox: false, enableClickSelection: false, } : undefined, defaultColDef: { suppressHeaderMenuButton: true, sortingOrder: ["desc", "asc", null], cellRendererSelector, }, maintainColumnOrder: true, localeText: { loadingError: "...", }, rowModelType: "serverSide", // cacheBlockSize should be the same as PlMultiSequenceAlignment limit // so that selectAll will add all rows to selection cacheBlockSize: 1000, maxBlocksInCache: 100, blockLoadDebounceMillis: 500, serverSideSortAllLevels: true, suppressServerSideFullWidthLoadingRow: true, getRowId: (params) => params.data.id, loading: true, loadingOverlayComponentParams: { variant: "not-ready", loadingText: loadingText, runningText: runningText, notReadyText: notReadyText, } satisfies PlAgOverlayLoadingParams, loadingOverlayComponent: PlOverlayLoading, noRowsOverlayComponent: PlOverlayNoRows, noRowsOverlayComponentParams: { text: noRowsText, } satisfies PlAgOverlayNoRowsParams, defaultCsvExportParams: { suppressQuotes: true, columnSeparator: "\t", fileName: "table.tsv", }, getContextMenuItems: (params) => (params.defaultItems ?? []).filter( (item) => item !== "export" && item !== "csvExport" && item !== "excelExport", ), onGridReady: (event) => { const api = event.api; autoSizeRowNumberColumn(api); const setGridOption = ( key: ManagedGridOptionKey, value: GridOptions[ManagedGridOptionKey], ) => { const options = { ...gridOptions.value }; options[key] = value; gridOptions.value = options; api.setGridOption(key, value); }; const updateGridOptions = (options: ManagedGridOptions) => { gridOptions.value = { ...gridOptions.value, ...options, }; api.updateGridOptions(options); }; gridApi.value = new Proxy(api, { get(target, prop, receiver) { switch (prop) { case "setGridOption": return setGridOption; case "updateGridOptions": return updateGridOptions; default: return Reflect.get(target, prop, receiver); } }, }); }, onSelectionChanged: (event) => { if (!isNil(selection.value)) { const state = event.api.getServerSideSelectionState(); const selectedKeys = state?.toggledNodes?.map((nodeId) => parseJson(nodeId as PlTableRowIdJson)) ?? []; if (!isJsonEqual(selection.value.selectedKeys, selectedKeys)) { selection.value = { ...selection.value, selectedKeys }; } } }, onRowDoubleClicked: (_event) => { throw new Error("not overrided onRowDoubleClicked"); }, onStateUpdated: (_event) => { throw new Error("not overrided onStateUpdated"); }, onGridPreDestroyed: (_event) => { throw new Error("not overrided onGridPreDestroyed"); }, }); return { gridApi, gridOptions }; }