@platforma-sdk/ui-vue 1.67.0 → 1.68.0
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/.turbo/turbo-build.log +19 -19
- package/.turbo/turbo-formatter$colon$check.log +2 -2
- package/.turbo/turbo-linter$colon$check.log +2 -2
- package/.turbo/turbo-types$colon$check.log +1 -1
- package/CHANGELOG.md +22 -0
- package/dist/components/PlAgCsvExporter/PlAgCsvExporter.js.map +1 -1
- package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue.d.ts +2 -0
- package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue.d.ts.map +1 -1
- package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue2.js +25 -17
- package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue2.js.map +1 -1
- package/dist/components/PlAgCsvExporter/export-csv.d.ts +27 -1
- package/dist/components/PlAgCsvExporter/export-csv.d.ts.map +1 -1
- package/dist/components/PlAgCsvExporter/export-csv.js +31 -33
- package/dist/components/PlAgCsvExporter/export-csv.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.style.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +68 -64
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/compositions/useGrid.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/compositions/useGrid.js +1 -1
- package/dist/components/PlAgDataTable/compositions/useGrid.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-source-v2.js +2 -2
- package/dist/components/PlAgDataTable/sources/table-source-v2.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js.map +1 -1
- package/dist/composition/usePlugin.d.ts.map +1 -0
- package/dist/{usePlugin.js → composition/usePlugin.js} +2 -2
- package/dist/composition/usePlugin.js.map +1 -0
- package/dist/composition/useServices.d.ts +2 -0
- package/dist/composition/useServices.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/internal/createAppV3.d.ts +2 -3
- package/dist/internal/createAppV3.d.ts.map +1 -1
- package/dist/internal/createAppV3.js +1 -1
- package/dist/internal/createAppV3.js.map +1 -1
- package/dist/internal/service_factories.d.ts +1 -0
- package/dist/internal/service_factories.d.ts.map +1 -1
- package/dist/internal/service_factories.js +2 -1
- package/dist/internal/service_factories.js.map +1 -1
- package/dist/lib.d.ts +2 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -1
- package/package.json +8 -8
- package/src/components/PlAgCsvExporter/PlAgCsvExporter.vue +16 -3
- package/src/components/PlAgCsvExporter/export-csv.ts +101 -64
- package/src/components/PlAgDataTable/PlAgDataTableV2.vue +6 -1
- package/src/components/PlAgDataTable/compositions/useGrid.ts +4 -1
- package/src/components/PlAgDataTable/sources/table-source-v2.ts +2 -2
- package/src/{usePlugin.ts → composition/usePlugin.ts} +1 -1
- package/src/composition/useServices.ts +5 -0
- package/src/internal/createAppV3.ts +4 -4
- package/src/internal/service_factories.ts +1 -0
- package/src/lib.ts +2 -2
- package/dist/usePlugin.d.ts.map +0 -1
- package/dist/usePlugin.js.map +0 -1
- /package/dist/{usePlugin.d.ts → composition/usePlugin.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-source-v2.js","names":[],"sources":["../../../../src/components/PlAgDataTable/sources/table-source-v2.ts"],"sourcesContent":["import type {\n AxesSpec,\n PTableColumnId,\n PTableColumnSpecAxis,\n PTableColumnSpecColumn,\n PTableHandle,\n PTableValue,\n} from \"@platforma-sdk/model\";\nimport {\n canonicalizeJson,\n getAxisId,\n pTableValue,\n type PFrameDriver,\n type PlDataTableSheet,\n type PTableVector,\n type AxisId,\n type PTableColumnSpec,\n type PTableKey,\n type PlTableColumnId,\n type PlTableColumnIdJson,\n isLabelColumn as isLabelColumnSpec,\n isLinkerColumn as isLinkerColumnSpec,\n isColumnHidden,\n isColumnOptional,\n matchAxisId,\n readAnnotation,\n readAnnotationJson,\n Annotation,\n ValueType,\n getPTableColumnId,\n} from \"@platforma-sdk/model\";\nimport type {\n CellStyle,\n ColDef,\n GridApi,\n ICellRendererParams,\n IServerSideDatasource,\n IServerSideGetRowsParams,\n ManagedGridOptions,\n} from \"ag-grid-enterprise\";\nimport type { PlAgHeaderComponentParams, PlAgHeaderComponentType } from \"../../PlAgColumnHeader\";\nimport { PlAgColumnHeader } from \"../../PlAgColumnHeader\";\nimport { PlAgTextAndButtonCell } from \"../../PlAgTextAndButtonCell\";\nimport type { PlAgDataTableV2Row, PlTableRowId } from \"../types\";\nimport { PTableHidden } from \"./common\";\nimport { defaultMainMenuItems } from \"./menu-items\";\nimport { makeRowNumberColDef, PlAgDataTableRowNumberColId } from \"./row-number\";\nimport { getColumnRenderingSpec } from \"./value-rendering\";\nimport type { Ref } from \"vue\";\nimport { isJsonEqual } from \"@milaboratories/helpers\";\nimport type { DeferredCircular } from \"./focus-row\";\nimport { isNil, uniq } from \"es-toolkit\";\n\nexport function isLabelColumn(column: PTableColumnSpec): column is PTableColumnSpecColumn {\n return column.type === \"column\" && isLabelColumnSpec(column.spec);\n}\n\n/** Convert columnar data from the driver to rows, used by ag-grid */\nfunction columns2rows(\n fields: number[],\n columns: PTableVector[],\n fieldResultMapping: number[],\n axesResultIndices: number[],\n): PlAgDataTableV2Row[] {\n const rowData: PlAgDataTableV2Row[] = [];\n for (let rowIdx = 0; rowIdx < columns[0].data.length; ++rowIdx) {\n const axesKey: PTableKey = axesResultIndices.map((ri) => pTableValue(columns[ri], rowIdx));\n const id = canonicalizeJson<PlTableRowId>(axesKey);\n const row = fields.reduce<PlAgDataTableV2Row>(\n (acc, field, colIdx) => {\n acc[field.toString() as `${number}`] =\n fieldResultMapping[colIdx] === -1\n ? PTableHidden\n : pTableValue(columns[fieldResultMapping[colIdx]], rowIdx);\n return acc;\n },\n { id, axesKey },\n );\n\n rowData.push(row);\n }\n return rowData;\n}\n\n/** Calculate GridOptions for selected p-table data source */\nexport async function calculateGridOptions({\n generation,\n pfDriver,\n sheets,\n fullTableHandle,\n visibleTableHandle,\n dataRenderedTracker,\n hiddenColIds,\n cellButtonAxisParams,\n}: {\n sheets: PlDataTableSheet[];\n pfDriver: PFrameDriver;\n generation: Ref<number>;\n fullTableHandle: PTableHandle;\n visibleTableHandle: PTableHandle;\n dataRenderedTracker: DeferredCircular<GridApi<PlAgDataTableV2Row>>;\n hiddenColIds?: PlTableColumnIdJson[];\n cellButtonAxisParams?: PlAgCellButtonAxisParams;\n}): Promise<\n Pick<ManagedGridOptions<PlAgDataTableV2Row>, \"columnDefs\" | \"serverSideDatasource\"> & {\n axesSpec: AxesSpec;\n }\n> {\n const stateGeneration = generation.value;\n\n // get specs of the full table\n const [tableSpecs, visibleTableSpecs] = await Promise.all([\n pfDriver.getSpec(fullTableHandle),\n pfDriver.getSpec(visibleTableHandle),\n ]);\n\n if (stateGeneration !== generation.value) throw new Error(\"table state generation changed\");\n\n // index mapping from full specs to visible subset (hidden columns → -1)\n const specsToVisibleSpecsMapping = buildSpecsToVisibleSpecsMapping(tableSpecs, visibleTableSpecs);\n\n const isPartitionedAxis = createPartitionedAxisPredicate(sheets);\n\n // label columns indexed by labeled axis (for axis→label replacement later)\n const getLabelColumnIndex = collectLabelColumnsByAxis(tableSpecs, isPartitionedAxis);\n\n // displayable column indices ordered: axes first, then columns by OrderPriority\n const fields = sortIndicesByTypeAndPriority(\n selectDisplayableIndices(tableSpecs, isPartitionedAxis),\n tableSpecs,\n );\n\n // same as fields, but each axis replaced by its label column index when available\n const indices = replaceAxesWithLabelColumns(fields, tableSpecs, getLabelColumnIndex);\n\n // default hidden columns derived from Optional annotation when no saved state\n const resolvedHiddenColIds =\n hiddenColIds ?? computeDefaultHiddenColIds(fields, indices, tableSpecs);\n\n const columnDefs: ColDef<PlAgDataTableV2Row, PTableValue | PTableHidden>[] = [\n makeRowNumberColDef(),\n ...fields.map((field, index) =>\n makeColDef(\n field,\n tableSpecs[field],\n tableSpecs[indices[index]],\n resolvedHiddenColIds,\n cellButtonAxisParams,\n ),\n ),\n ];\n\n // axes — taken directly from visible table (always present as part of join)\n const visibleAxes = collectVisibleAxes(visibleTableSpecs);\n\n // request indices: non-hidden display fields + visible axes for row selection keys.\n // Axes replaced by label columns request label data (display); original axis values\n // are fetched via visibleAxes (row keys).\n const { requestIndices, axesResultIndices, fieldResultMapping } = buildRequestIndices(\n indices,\n visibleAxes.map(([idx]) => idx),\n specsToVisibleSpecsMapping,\n );\n\n let rowCount = -1;\n let lastParams: IServerSideGetRowsParams | undefined = undefined;\n const serverSideDatasource: IServerSideDatasource<PlAgDataTableV2Row> = {\n getRows: async (params: IServerSideGetRowsParams) => {\n if (stateGeneration !== generation.value) return params.fail();\n try {\n if (rowCount === -1) {\n const ptShape = await pfDriver.getShape(visibleTableHandle);\n if (stateGeneration !== generation.value || params.api.isDestroyed())\n return params.fail();\n rowCount = ptShape.rows;\n }\n\n if (rowCount == 0) {\n params.success({ rowData: [], rowCount });\n // Warning: AgGrid cannot show two overlays at once,\n // so first hide loading overlay, then show no rows overlay\n params.api.setGridOption(\"loading\", false);\n params.api.showNoRowsOverlay();\n return;\n }\n\n // If sort has changed - show skeletons instead of data\n if (lastParams && !isJsonEqual(lastParams.request.sortModel, params.request.sortModel)) {\n return params.success({ rowData: [], rowCount });\n }\n lastParams = params;\n\n let length = 0;\n let rowData: PlAgDataTableV2Row[] = [];\n if (\n rowCount > 0 &&\n params.request.startRow !== undefined &&\n params.request.endRow !== undefined\n ) {\n length = Math.min(rowCount, params.request.endRow) - params.request.startRow;\n if (length > 0) {\n const data = await pfDriver.getData(visibleTableHandle, requestIndices, {\n offset: params.request.startRow,\n length,\n });\n if (stateGeneration !== generation.value || params.api.isDestroyed())\n return params.fail();\n rowData = columns2rows(fields, data, fieldResultMapping, axesResultIndices);\n }\n }\n\n params.success({ rowData, rowCount });\n params.api.autoSizeColumns(\n params.api\n .getAllDisplayedColumns()\n .filter((column) => column.getColId() !== PlAgDataTableRowNumberColId),\n );\n params.api.setGridOption(\"loading\", false);\n dataRenderedTracker.resolve(params.api);\n } catch (error: unknown) {\n if (stateGeneration !== generation.value || params.api.isDestroyed()) return params.fail();\n params.api.setGridOption(\"loading\", true);\n params.fail();\n console.trace(error);\n }\n },\n };\n\n return {\n axesSpec: visibleAxes.map(([, { spec }]) => spec),\n columnDefs,\n serverSideDatasource,\n };\n}\n\nexport type PlAgCellButtonAxisParams = {\n showCellButtonForAxisId?: AxisId;\n cellButtonInvokeRowsOnDoubleClick?: boolean;\n trigger: (key?: PTableKey) => void;\n};\n\n/**\n * Calculates column definition for a given p-table column\n */\nexport function makeColDef(\n iCol: number,\n spec: PTableColumnSpec,\n labeledSpec: PTableColumnSpec,\n hiddenColIds: PlTableColumnIdJson[] | undefined,\n cellButtonAxisParams?: PlAgCellButtonAxisParams,\n): ColDef<PlAgDataTableV2Row, PTableValue | PTableHidden> {\n const colId = canonicalizeJson<PlTableColumnId>({\n source: spec,\n labeled: labeledSpec,\n });\n const valueType = spec.type === \"axis\" ? spec.spec.type : spec.spec.valueType;\n const columnRenderingSpec = getColumnRenderingSpec(spec);\n const cellStyle: CellStyle = {};\n if (columnRenderingSpec.fontFamily) {\n if (columnRenderingSpec.fontFamily === \"monospace\") {\n cellStyle.fontFamily = \"Spline Sans Mono\";\n cellStyle.fontWeight = 300;\n } else {\n cellStyle.fontFamily = columnRenderingSpec.fontFamily;\n }\n }\n const headerName =\n readAnnotation(labeledSpec.spec, Annotation.Label)?.trim() ??\n readAnnotation(spec.spec, Annotation.Label)?.trim() ??\n `Unlabeled ${spec.type} ${iCol}`;\n\n return {\n colId,\n mainMenuItems: defaultMainMenuItems,\n context: spec,\n field: `${iCol}`,\n headerName,\n lockPosition: spec.type === \"axis\",\n hide: hiddenColIds !== undefined && hiddenColIds.includes(colId),\n valueFormatter: columnRenderingSpec.valueFormatter,\n headerComponent: PlAgColumnHeader,\n cellRendererSelector: cellButtonAxisParams?.showCellButtonForAxisId\n ? (params: ICellRendererParams) => {\n if (spec.type !== \"axis\") return;\n\n const axisId = (params.colDef?.context as PTableColumnSpec)?.id as AxisId;\n if (isJsonEqual(axisId, cellButtonAxisParams.showCellButtonForAxisId)) {\n return {\n component: PlAgTextAndButtonCell,\n params: {\n invokeRowsOnDoubleClick: cellButtonAxisParams.cellButtonInvokeRowsOnDoubleClick,\n onClick: (params: ICellRendererParams<PlAgDataTableV2Row>) => {\n cellButtonAxisParams.trigger(params.data?.axesKey);\n },\n },\n };\n }\n }\n : undefined,\n cellStyle,\n headerComponentParams: {\n type: ((): PlAgHeaderComponentType => {\n switch (valueType) {\n case ValueType.Int:\n case ValueType.Long:\n case ValueType.Float:\n case ValueType.Double:\n return \"Number\";\n case ValueType.String:\n case ValueType.Bytes:\n return \"Text\";\n default:\n throw Error(`unsupported data type: ${valueType}`);\n }\n })(),\n tooltip:\n readAnnotation(spec.spec, Annotation.Description)?.trim() ??\n readAnnotation(labeledSpec.spec, Annotation.Description)?.trim(),\n info:\n readAnnotation(spec.spec, Annotation.Table.Info)?.trim() ??\n readAnnotation(labeledSpec.spec, Annotation.Table.Info)?.trim(),\n } satisfies PlAgHeaderComponentParams,\n cellDataType: (() => {\n switch (valueType) {\n case ValueType.Int:\n case ValueType.Long:\n case ValueType.Float:\n case ValueType.Double:\n return \"number\";\n case ValueType.String:\n case ValueType.Bytes:\n return \"text\";\n default:\n throw Error(`unsupported data type: ${valueType}`);\n }\n })(),\n };\n}\n\ntype LabelColumnLookup = (axisId: AxisId) => number;\n\n/** Build index mapping from full tableSpecs to their position in visibleTableSpecs (missing → -1). */\nfunction buildSpecsToVisibleSpecsMapping(\n tableSpecs: PTableColumnSpec[],\n visibleTableSpecs: PTableColumnSpec[],\n): Map<number, number> {\n const specId = (spec: PTableColumnSpec) =>\n canonicalizeJson<PTableColumnId>(getPTableColumnId(spec));\n const visibleSpecsMap = new Map(\n visibleTableSpecs.entries().map(([i, spec]) => [specId(spec), i] as const),\n );\n return new Map(\n tableSpecs.entries().map(([i, spec]) => {\n const visibleSpecIdx = visibleSpecsMap.get(specId(spec));\n return [i, isNil(visibleSpecIdx) ? -1 : visibleSpecIdx];\n }),\n );\n}\n\n/** Predicate that returns true when an axis is one of the sheet partition axes. */\nfunction createPartitionedAxisPredicate(sheets: PlDataTableSheet[]): (axisId: AxisId) => boolean {\n const sheetAxesIds = sheets.map((sheet) => getAxisId(sheet.axis));\n return (axisId) => sheetAxesIds.some((id) => matchAxisId(id, axisId));\n}\n\n/**\n * Collect label columns (skipping partitioned axes and duplicates) and return a\n * lookup function that resolves labeled axisId → label column index (or -1).\n */\nfunction collectLabelColumnsByAxis(\n tableSpecs: PTableColumnSpec[],\n isPartitionedAxis: (axisId: AxisId) => boolean,\n): LabelColumnLookup {\n const labelColumns: { axisId: AxisId; labelColumnIdx: number }[] = [];\n for (const [i, spec] of tableSpecs.entries()) {\n if (spec.type !== \"column\" || !isLabelColumnSpec(spec.spec)) continue;\n const labeledAxisId = getAxisId(spec.spec.axesSpec[0]);\n if (isPartitionedAxis(labeledAxisId)) continue;\n if (labelColumns.some((info) => matchAxisId(info.axisId, labeledAxisId))) {\n console.warn(`multiple label columns match axisId: ${JSON.stringify(labeledAxisId)}`);\n continue;\n }\n labelColumns.push({ axisId: labeledAxisId, labelColumnIdx: i });\n }\n return (axisId) =>\n labelColumns.find((info) => matchAxisId(info.axisId, axisId))?.labelColumnIdx ?? -1;\n}\n\n/** Indices of columns to display: drop partitioned axes, label/linker columns, hidden columns. */\nfunction selectDisplayableIndices(\n tableSpecs: PTableColumnSpec[],\n isPartitionedAxis: (axisId: AxisId) => boolean,\n): number[] {\n return tableSpecs\n .entries()\n .filter(([, spec]) => {\n switch (spec.type) {\n case \"axis\":\n return !isPartitionedAxis(spec.id);\n case \"column\":\n return (\n !isLabelColumnSpec(spec.spec) &&\n !isColumnHidden(spec.spec) &&\n !isLinkerColumnSpec(spec.spec)\n );\n }\n })\n .map(([i]) => i)\n .toArray();\n}\n\n/** Sort: axes first, then columns by OrderPriority annotation (higher priority = further left). */\nfunction sortIndicesByTypeAndPriority(indices: number[], tableSpecs: PTableColumnSpec[]): number[] {\n const priorityOf = (i: number): number => {\n const spec = tableSpecs[i];\n return spec.type === \"column\"\n ? (readAnnotationJson(spec.spec, Annotation.Table.OrderPriority) ?? 0)\n : 0;\n };\n return [...indices].sort((a, b) => {\n if (tableSpecs[a].type !== tableSpecs[b].type) {\n return tableSpecs[a].type === \"axis\" ? -1 : 1;\n }\n return priorityOf(b) - priorityOf(a);\n });\n}\n\n/** For each axis entry substitute the index of its matching label column when one exists. */\nfunction replaceAxesWithLabelColumns(\n fields: number[],\n tableSpecs: PTableColumnSpec[],\n getLabelColumnIndex: LabelColumnLookup,\n): number[] {\n return fields.map((i) => {\n const spec = tableSpecs[i];\n const labelIdx = spec.type === \"axis\" ? getLabelColumnIndex(spec.id) : -1;\n return labelIdx === -1 ? i : labelIdx;\n });\n}\n\n/** Default hidden col ids built from columns marked with the Optional annotation. */\nfunction computeDefaultHiddenColIds(\n fields: number[],\n indices: number[],\n tableSpecs: PTableColumnSpec[],\n): PlTableColumnIdJson[] {\n return fields.reduce<PlTableColumnIdJson[]>((acc, field, i) => {\n const spec = tableSpecs[field];\n if (spec.type !== \"column\" || !isColumnOptional(spec.spec)) return acc;\n const labeledSpec = tableSpecs[indices[i]];\n return [...acc, canonicalizeJson<PlTableColumnId>({ source: spec, labeled: labeledSpec })];\n }, []);\n}\n\n/** Extract axis indices and specs from the visible table (always present as part of join). */\nfunction collectVisibleAxes(\n visibleTableSpecs: PTableColumnSpec[],\n): [number, PTableColumnSpecAxis][] {\n return visibleTableSpecs\n .entries()\n .filter((entry): entry is [number, PTableColumnSpecAxis] => entry[1].type === \"axis\")\n .toArray();\n}\n\n/**\n * Compose request indices for the visible table:\n * non-hidden display fields first, then visible axes (deduplicated).\n * Returns fieldResultMapping (display field → position in requestIndices, -1 if not requested)\n * and axesResultIndices (visible axis → position in requestIndices).\n */\nfunction buildRequestIndices(\n indices: number[],\n visibleAxesIndices: number[],\n specsToVisibleSpecsMapping: Map<number, number>,\n): {\n requestIndices: number[];\n axesResultIndices: number[];\n fieldResultMapping: number[];\n} {\n const resolved = indices.map((displayField) => {\n const idx = specsToVisibleSpecsMapping.get(displayField);\n return isNil(idx) || idx === -1 ? null : idx;\n });\n const requestIndices = uniq([\n ...resolved.filter((v): v is number => v !== null),\n ...visibleAxesIndices,\n ]);\n const fieldResultMapping = resolved.map((v) => (v === null ? -1 : requestIndices.indexOf(v)));\n const axesResultIndices = visibleAxesIndices.map((vi) => requestIndices.indexOf(vi));\n\n return { requestIndices, axesResultIndices, fieldResultMapping };\n}\n"],"mappings":";;;;;;;;;;;;;AA0DA,SAAS,EACP,GACA,GACA,GACA,GACsB;CACtB,IAAM,IAAgC,EAAE;AACxC,MAAK,IAAI,IAAS,GAAG,IAAS,EAAQ,GAAG,KAAK,QAAQ,EAAE,GAAQ;EAC9D,IAAM,IAAqB,EAAkB,KAAK,MAAO,EAAY,EAAQ,IAAK,EAAO,CAAC,EACpF,IAAK,EAA+B,EAAQ,EAC5C,IAAM,EAAO,QAChB,GAAK,GAAO,OACX,EAAI,EAAM,UAAU,IAClB,EAAmB,OAAY,KAC3B,IACA,EAAY,EAAQ,EAAmB,KAAU,EAAO,EACvD,IAET;GAAE;GAAI;GAAS,CAChB;AAED,IAAQ,KAAK,EAAI;;AAEnB,QAAO;;AAIT,eAAsB,EAAqB,EACzC,eACA,aACA,WACA,oBACA,uBACA,wBACA,iBACA,2BAcA;CACA,IAAM,IAAkB,EAAW,OAG7B,CAAC,GAAY,KAAqB,MAAM,QAAQ,IAAI,CACxD,EAAS,QAAQ,EAAgB,EACjC,EAAS,QAAQ,EAAmB,CACrC,CAAC;AAEF,KAAI,MAAoB,EAAW,MAAO,OAAU,MAAM,iCAAiC;CAG3F,IAAM,IAA6B,EAAgC,GAAY,EAAkB,EAE3F,IAAoB,EAA+B,EAAO,EAG1D,IAAsB,EAA0B,GAAY,EAAkB,EAG9E,IAAS,EACb,EAAyB,GAAY,EAAkB,EACvD,EACD,EAGK,IAAU,EAA4B,GAAQ,GAAY,EAAoB,EAG9E,IACJ,KAAgB,EAA2B,GAAQ,GAAS,EAAW,EAEnE,IAAuE,CAC3E,GAAqB,EACrB,GAAG,EAAO,KAAK,GAAO,MACpB,EACE,GACA,EAAW,IACX,EAAW,EAAQ,KACnB,GACA,EACD,CACF,CACF,EAGK,IAAc,EAAmB,EAAkB,EAKnD,EAAE,mBAAgB,sBAAmB,0BAAuB,EAChE,GACA,EAAY,KAAK,CAAC,OAAS,EAAI,EAC/B,EACD,EAEG,IAAW,IACX;AA+DJ,QAAO;EACL,UAAU,EAAY,KAAK,GAAG,EAAE,eAAY,EAAK;EACjD;EACA,sBAjEsE,EACtE,SAAS,OAAO,MAAqC;AACnD,OAAI,MAAoB,EAAW,MAAO,QAAO,EAAO,MAAM;AAC9D,OAAI;AACF,QAAI,MAAa,IAAI;KACnB,IAAM,IAAU,MAAM,EAAS,SAAS,EAAmB;AAC3D,SAAI,MAAoB,EAAW,SAAS,EAAO,IAAI,aAAa,CAClE,QAAO,EAAO,MAAM;AACtB,SAAW,EAAQ;;AAGrB,QAAI,KAAY,GAAG;AAKjB,KAJA,EAAO,QAAQ;MAAE,SAAS,EAAE;MAAE;MAAU,CAAC,EAGzC,EAAO,IAAI,cAAc,WAAW,GAAM,EAC1C,EAAO,IAAI,mBAAmB;AAC9B;;AAIF,QAAI,KAAc,CAAC,EAAY,EAAW,QAAQ,WAAW,EAAO,QAAQ,UAAU,CACpF,QAAO,EAAO,QAAQ;KAAE,SAAS,EAAE;KAAE;KAAU,CAAC;AAElD,QAAa;IAEb,IAAI,IAAS,GACT,IAAgC,EAAE;AACtC,QACE,IAAW,KACX,EAAO,QAAQ,aAAa,KAAA,KAC5B,EAAO,QAAQ,WAAW,KAAA,MAE1B,IAAS,KAAK,IAAI,GAAU,EAAO,QAAQ,OAAO,GAAG,EAAO,QAAQ,UAChE,IAAS,IAAG;KACd,IAAM,IAAO,MAAM,EAAS,QAAQ,GAAoB,GAAgB;MACtE,QAAQ,EAAO,QAAQ;MACvB;MACD,CAAC;AACF,SAAI,MAAoB,EAAW,SAAS,EAAO,IAAI,aAAa,CAClE,QAAO,EAAO,MAAM;AACtB,SAAU,EAAa,GAAQ,GAAM,GAAoB,EAAkB;;AAW/E,IAPA,EAAO,QAAQ;KAAE;KAAS;KAAU,CAAC,EACrC,EAAO,IAAI,gBACT,EAAO,IACJ,wBAAwB,CACxB,QAAQ,MAAW,EAAO,UAAU,KAAK,EAA4B,CACzE,EACD,EAAO,IAAI,cAAc,WAAW,GAAM,EAC1C,EAAoB,QAAQ,EAAO,IAAI;YAChC,GAAgB;AACvB,QAAI,MAAoB,EAAW,SAAS,EAAO,IAAI,aAAa,CAAE,QAAO,EAAO,MAAM;AAG1F,IAFA,EAAO,IAAI,cAAc,WAAW,GAAK,EACzC,EAAO,MAAM,EACb,QAAQ,MAAM,EAAM;;KAGzB;EAMA;;AAYH,SAAgB,EACd,GACA,GACA,GACA,GACA,GACwD;CACxD,IAAM,IAAQ,EAAkC;EAC9C,QAAQ;EACR,SAAS;EACV,CAAC,EACI,IAAY,EAAK,SAAS,SAAS,EAAK,KAAK,OAAO,EAAK,KAAK,WAC9D,IAAsB,EAAuB,EAAK,EAClD,IAAuB,EAAE;AAC/B,CAAI,EAAoB,eAClB,EAAoB,eAAe,eACrC,EAAU,aAAa,oBACvB,EAAU,aAAa,OAEvB,EAAU,aAAa,EAAoB;CAG/C,IAAM,IACJ,EAAe,EAAY,MAAM,EAAW,MAAM,EAAE,MAAM,IAC1D,EAAe,EAAK,MAAM,EAAW,MAAM,EAAE,MAAM,IACnD,aAAa,EAAK,KAAK,GAAG;AAE5B,QAAO;EACL;EACA,eAAe;EACf,SAAS;EACT,OAAO,GAAG;EACV;EACA,cAAc,EAAK,SAAS;EAC5B,MAAM,MAAiB,KAAA,KAAa,EAAa,SAAS,EAAM;EAChE,gBAAgB,EAAoB;EACpC,iBAAiB;EACjB,sBAAsB,GAAsB,2BACvC,MAAgC;AAC/B,OAAI,EAAK,SAAS,OAAQ;GAE1B,IAAM,IAAU,EAAO,QAAQ,SAA8B;AAC7D,OAAI,EAAY,GAAQ,EAAqB,wBAAwB,CACnE,QAAO;IACL,WAAW;IACX,QAAQ;KACN,yBAAyB,EAAqB;KAC9C,UAAU,MAAoD;AAC5D,QAAqB,QAAQ,EAAO,MAAM,QAAQ;;KAErD;IACF;MAGL,KAAA;EACJ;EACA,uBAAuB;GACrB,aAAsC;AACpC,YAAQ,GAAR;KACE,KAAK,EAAU;KACf,KAAK,EAAU;KACf,KAAK,EAAU;KACf,KAAK,EAAU,OACb,QAAO;KACT,KAAK,EAAU;KACf,KAAK,EAAU,MACb,QAAO;KACT,QACE,OAAM,MAAM,0BAA0B,IAAY;;OAEpD;GACJ,SACE,EAAe,EAAK,MAAM,EAAW,YAAY,EAAE,MAAM,IACzD,EAAe,EAAY,MAAM,EAAW,YAAY,EAAE,MAAM;GAClE,MACE,EAAe,EAAK,MAAM,EAAW,MAAM,KAAK,EAAE,MAAM,IACxD,EAAe,EAAY,MAAM,EAAW,MAAM,KAAK,EAAE,MAAM;GAClE;EACD,qBAAqB;AACnB,WAAQ,GAAR;IACE,KAAK,EAAU;IACf,KAAK,EAAU;IACf,KAAK,EAAU;IACf,KAAK,EAAU,OACb,QAAO;IACT,KAAK,EAAU;IACf,KAAK,EAAU,MACb,QAAO;IACT,QACE,OAAM,MAAM,0BAA0B,IAAY;;MAEpD;EACL;;AAMH,SAAS,EACP,GACA,GACqB;CACrB,IAAM,KAAU,MACd,EAAiC,EAAkB,EAAK,CAAC,EACrD,IAAkB,IAAI,IAC1B,EAAkB,SAAS,CAAC,KAAK,CAAC,GAAG,OAAU,CAAC,EAAO,EAAK,EAAE,EAAE,CAAU,CAC3E;AACD,QAAO,IAAI,IACT,EAAW,SAAS,CAAC,KAAK,CAAC,GAAG,OAAU;EACtC,IAAM,IAAiB,EAAgB,IAAI,EAAO,EAAK,CAAC;AACxD,SAAO,CAAC,GAAG,EAAM,EAAe,GAAG,KAAK,EAAe;GACvD,CACH;;AAIH,SAAS,EAA+B,GAAyD;CAC/F,IAAM,IAAe,EAAO,KAAK,MAAU,EAAU,EAAM,KAAK,CAAC;AACjE,SAAQ,MAAW,EAAa,MAAM,MAAO,EAAY,GAAI,EAAO,CAAC;;AAOvE,SAAS,EACP,GACA,GACmB;CACnB,IAAM,IAA6D,EAAE;AACrE,MAAK,IAAM,CAAC,GAAG,MAAS,EAAW,SAAS,EAAE;AAC5C,MAAI,EAAK,SAAS,YAAY,CAAC,EAAkB,EAAK,KAAK,CAAE;EAC7D,IAAM,IAAgB,EAAU,EAAK,KAAK,SAAS,GAAG;AAClD,SAAkB,EAAc,EACpC;OAAI,EAAa,MAAM,MAAS,EAAY,EAAK,QAAQ,EAAc,CAAC,EAAE;AACxE,YAAQ,KAAK,wCAAwC,KAAK,UAAU,EAAc,GAAG;AACrF;;AAEF,KAAa,KAAK;IAAE,QAAQ;IAAe,gBAAgB;IAAG,CAAC;;;AAEjE,SAAQ,MACN,EAAa,MAAM,MAAS,EAAY,EAAK,QAAQ,EAAO,CAAC,EAAE,kBAAkB;;AAIrF,SAAS,EACP,GACA,GACU;AACV,QAAO,EACJ,SAAS,CACT,QAAQ,GAAG,OAAU;AACpB,UAAQ,EAAK,MAAb;GACE,KAAK,OACH,QAAO,CAAC,EAAkB,EAAK,GAAG;GACpC,KAAK,SACH,QACE,CAAC,EAAkB,EAAK,KAAK,IAC7B,CAAC,EAAe,EAAK,KAAK,IAC1B,CAAC,EAAmB,EAAK,KAAK;;GAGpC,CACD,KAAK,CAAC,OAAO,EAAE,CACf,SAAS;;AAId,SAAS,EAA6B,GAAmB,GAA0C;CACjG,IAAM,KAAc,MAAsB;EACxC,IAAM,IAAO,EAAW;AACxB,SAAO,EAAK,SAAS,WAChB,EAAmB,EAAK,MAAM,EAAW,MAAM,cAAc,IAAI,IAClE;;AAEN,QAAO,CAAC,GAAG,EAAQ,CAAC,MAAM,GAAG,MACvB,EAAW,GAAG,SAAS,EAAW,GAAG,OAGlC,EAAW,EAAE,GAAG,EAAW,EAAE,GAF3B,EAAW,GAAG,SAAS,SAAS,KAAK,EAG9C;;AAIJ,SAAS,EACP,GACA,GACA,GACU;AACV,QAAO,EAAO,KAAK,MAAM;EACvB,IAAM,IAAO,EAAW,IAClB,IAAW,EAAK,SAAS,SAAS,EAAoB,EAAK,GAAG,GAAG;AACvE,SAAO,MAAa,KAAK,IAAI;GAC7B;;AAIJ,SAAS,EACP,GACA,GACA,GACuB;AACvB,QAAO,EAAO,QAA+B,GAAK,GAAO,MAAM;EAC7D,IAAM,IAAO,EAAW;AACxB,MAAI,EAAK,SAAS,YAAY,CAAC,EAAiB,EAAK,KAAK,CAAE,QAAO;EACnE,IAAM,IAAc,EAAW,EAAQ;AACvC,SAAO,CAAC,GAAG,GAAK,EAAkC;GAAE,QAAQ;GAAM,SAAS;GAAa,CAAC,CAAC;IACzF,EAAE,CAAC;;AAIR,SAAS,EACP,GACkC;AAClC,QAAO,EACJ,SAAS,CACT,QAAQ,MAAmD,EAAM,GAAG,SAAS,OAAO,CACpF,SAAS;;AASd,SAAS,EACP,GACA,GACA,GAKA;CACA,IAAM,IAAW,EAAQ,KAAK,MAAiB;EAC7C,IAAM,IAAM,EAA2B,IAAI,EAAa;AACxD,SAAO,EAAM,EAAI,IAAI,MAAQ,KAAK,OAAO;GACzC,EACI,IAAiB,EAAK,CAC1B,GAAG,EAAS,QAAQ,MAAmB,MAAM,KAAK,EAClD,GAAG,EACJ,CAAC,EACI,IAAqB,EAAS,KAAK,MAAO,MAAM,OAAO,KAAK,EAAe,QAAQ,EAAE,CAAE;AAG7F,QAAO;EAAE;EAAgB,mBAFC,EAAmB,KAAK,MAAO,EAAe,QAAQ,EAAG,CAAC;EAExC;EAAoB"}
|
|
1
|
+
{"version":3,"file":"table-source-v2.js","names":[],"sources":["../../../../src/components/PlAgDataTable/sources/table-source-v2.ts"],"sourcesContent":["import type {\n AxesSpec,\n PTableColumnId,\n PTableColumnSpecAxis,\n PTableColumnSpecColumn,\n PTableHandle,\n PTableValue,\n} from \"@platforma-sdk/model\";\nimport {\n canonicalizeJson,\n getAxisId,\n pTableValue,\n type PFrameDriver,\n type PlDataTableSheet,\n type PTableVector,\n type AxisId,\n type PTableColumnSpec,\n type PTableKey,\n type PlTableColumnId,\n type PlTableColumnIdJson,\n isLabelColumn as isLabelColumnSpec,\n isLinkerColumn as isLinkerColumnSpec,\n isColumnHidden,\n isColumnOptional,\n matchAxisId,\n readAnnotation,\n readAnnotationJson,\n Annotation,\n ValueType,\n getPTableColumnId,\n} from \"@platforma-sdk/model\";\nimport type {\n CellStyle,\n ColDef,\n GridApi,\n ICellRendererParams,\n IServerSideDatasource,\n IServerSideGetRowsParams,\n ManagedGridOptions,\n} from \"ag-grid-enterprise\";\nimport type { PlAgHeaderComponentParams, PlAgHeaderComponentType } from \"../../PlAgColumnHeader\";\nimport { PlAgColumnHeader } from \"../../PlAgColumnHeader\";\nimport { PlAgTextAndButtonCell } from \"../../PlAgTextAndButtonCell\";\nimport type { PlAgDataTableV2Row, PlTableRowId } from \"../types\";\nimport { PTableHidden } from \"./common\";\nimport { defaultMainMenuItems } from \"./menu-items\";\nimport { makeRowNumberColDef, PlAgDataTableRowNumberColId } from \"./row-number\";\nimport { getColumnRenderingSpec } from \"./value-rendering\";\nimport type { Ref } from \"vue\";\nimport { isJsonEqual } from \"@milaboratories/helpers\";\nimport type { DeferredCircular } from \"./focus-row\";\nimport { isNil, uniq } from \"es-toolkit\";\n\nexport function isLabelColumn(column: PTableColumnSpec): column is PTableColumnSpecColumn {\n return column.type === \"column\" && isLabelColumnSpec(column.spec);\n}\n\n/** Convert columnar data from the driver to rows, used by ag-grid */\nfunction columns2rows(\n fields: number[],\n columns: PTableVector[],\n fieldResultMapping: number[],\n axesResultIndices: number[],\n): PlAgDataTableV2Row[] {\n const rowData: PlAgDataTableV2Row[] = [];\n for (let rowIdx = 0; rowIdx < columns[0].data.length; ++rowIdx) {\n const axesKey: PTableKey = axesResultIndices.map((ri) => pTableValue(columns[ri], rowIdx));\n const id = canonicalizeJson<PlTableRowId>(axesKey);\n const row = fields.reduce<PlAgDataTableV2Row>(\n (acc, field, colIdx) => {\n acc[field.toString() as `${number}`] =\n fieldResultMapping[colIdx] === -1\n ? PTableHidden\n : pTableValue(columns[fieldResultMapping[colIdx]], rowIdx);\n return acc;\n },\n { id, axesKey },\n );\n\n rowData.push(row);\n }\n return rowData;\n}\n\n/** Calculate GridOptions for selected p-table data source */\nexport async function calculateGridOptions({\n generation,\n pfDriver,\n sheets,\n fullTableHandle,\n visibleTableHandle,\n dataRenderedTracker,\n hiddenColIds,\n cellButtonAxisParams,\n}: {\n sheets: PlDataTableSheet[];\n pfDriver: PFrameDriver;\n generation: Ref<number>;\n fullTableHandle: PTableHandle;\n visibleTableHandle: PTableHandle;\n dataRenderedTracker: DeferredCircular<GridApi<PlAgDataTableV2Row>>;\n hiddenColIds?: PlTableColumnIdJson[];\n cellButtonAxisParams?: PlAgCellButtonAxisParams;\n}): Promise<\n Pick<ManagedGridOptions<PlAgDataTableV2Row>, \"columnDefs\" | \"serverSideDatasource\"> & {\n axesSpec: AxesSpec;\n }\n> {\n const stateGeneration = generation.value;\n\n // get specs of the full table\n const [tableSpecs, visibleTableSpecs] = await Promise.all([\n pfDriver.getSpec(fullTableHandle),\n pfDriver.getSpec(visibleTableHandle),\n ]);\n\n if (stateGeneration !== generation.value) throw new Error(\"table state generation changed\");\n\n // index mapping from full specs to visible subset (hidden columns → -1)\n const specsToVisibleSpecsMapping = buildSpecsToVisibleSpecsMapping(tableSpecs, visibleTableSpecs);\n\n const isPartitionedAxis = createPartitionedAxisPredicate(sheets);\n\n // label columns indexed by labeled axis (for axis→label replacement later)\n const getLabelColumnIndex = collectLabelColumnsByAxis(tableSpecs, isPartitionedAxis);\n\n // displayable column indices ordered: axes first, then columns by OrderPriority\n const fields = sortIndicesByTypeAndPriority(\n selectDisplayableIndices(tableSpecs, isPartitionedAxis),\n tableSpecs,\n );\n\n // same as fields, but each axis replaced by its label column index when available\n const indices = replaceAxesWithLabelColumns(fields, tableSpecs, getLabelColumnIndex);\n\n // default hidden columns derived from Optional annotation when no saved state\n const resolvedHiddenColIds =\n hiddenColIds ?? computeDefaultHiddenColIds(fields, indices, tableSpecs);\n\n const columnDefs: ColDef<PlAgDataTableV2Row, PTableValue | PTableHidden>[] = [\n makeRowNumberColDef(),\n ...fields.map((field, index) =>\n makeColDef(\n field,\n tableSpecs[field],\n tableSpecs[indices[index]],\n resolvedHiddenColIds,\n cellButtonAxisParams,\n ),\n ),\n ];\n\n // axes — taken directly from visible table (always present as part of join)\n const visibleAxes = collectVisibleAxes(visibleTableSpecs);\n\n // request indices: non-hidden display fields + visible axes for row selection keys.\n // Axes replaced by label columns request label data (display); original axis values\n // are fetched via visibleAxes (row keys).\n const { requestIndices, axesResultIndices, fieldResultMapping } = buildRequestIndices(\n indices,\n visibleAxes.map(([idx]) => idx),\n specsToVisibleSpecsMapping,\n );\n\n let rowCount = -1;\n let lastParams: IServerSideGetRowsParams | undefined = undefined;\n const serverSideDatasource: IServerSideDatasource<PlAgDataTableV2Row> = {\n getRows: async (params: IServerSideGetRowsParams) => {\n if (stateGeneration !== generation.value) return params.fail();\n try {\n if (rowCount === -1) {\n const ptShape = await pfDriver.getShape(visibleTableHandle);\n if (stateGeneration !== generation.value || params.api.isDestroyed())\n return params.fail();\n rowCount = ptShape.rows;\n }\n\n if (rowCount == 0) {\n params.success({ rowData: [], rowCount });\n // Warning: AgGrid cannot show two overlays at once,\n // so first hide loading overlay, then show no rows overlay\n params.api.setGridOption(\"loading\", false);\n params.api.showNoRowsOverlay();\n return;\n }\n\n // If sort has changed - show skeletons instead of data\n if (lastParams && !isJsonEqual(lastParams.request.sortModel, params.request.sortModel)) {\n return params.success({ rowData: [], rowCount });\n }\n lastParams = params;\n\n let length = 0;\n let rowData: PlAgDataTableV2Row[] = [];\n if (\n rowCount > 0 &&\n params.request.startRow !== undefined &&\n params.request.endRow !== undefined\n ) {\n length = Math.min(rowCount, params.request.endRow) - params.request.startRow;\n if (length > 0) {\n const data = await pfDriver.getData(visibleTableHandle, requestIndices, {\n offset: params.request.startRow,\n length,\n });\n if (stateGeneration !== generation.value || params.api.isDestroyed())\n return params.fail();\n rowData = columns2rows(fields, data, fieldResultMapping, axesResultIndices);\n }\n }\n\n params.success({ rowData, rowCount });\n params.api.autoSizeColumns(\n params.api\n .getAllDisplayedColumns()\n .filter((column) => column.getColId() !== PlAgDataTableRowNumberColId),\n );\n params.api.setGridOption(\"loading\", false);\n dataRenderedTracker.resolve(params.api);\n } catch (error: unknown) {\n if (stateGeneration !== generation.value || params.api.isDestroyed()) return params.fail();\n params.api.setGridOption(\"loading\", true);\n params.fail();\n console.trace(error);\n }\n },\n };\n\n return {\n axesSpec: visibleAxes.map(([, { spec }]) => spec),\n columnDefs,\n serverSideDatasource,\n };\n}\n\nexport type PlAgCellButtonAxisParams = {\n showCellButtonForAxisId?: AxisId;\n cellButtonInvokeRowsOnDoubleClick?: boolean;\n trigger: (key?: PTableKey) => void;\n};\n\n/**\n * Calculates column definition for a given p-table column\n */\nexport function makeColDef(\n iCol: number,\n spec: PTableColumnSpec,\n labeledSpec: PTableColumnSpec,\n hiddenColIds: PlTableColumnIdJson[] | undefined,\n cellButtonAxisParams?: PlAgCellButtonAxisParams,\n): ColDef<PlAgDataTableV2Row, PTableValue | PTableHidden> {\n const colId = canonicalizeJson<PlTableColumnId>({\n source: spec,\n labeled: labeledSpec,\n });\n const valueType = spec.type === \"axis\" ? spec.spec.type : spec.spec.valueType;\n const columnRenderingSpec = getColumnRenderingSpec(spec);\n const cellStyle: CellStyle = {};\n if (columnRenderingSpec.fontFamily) {\n if (columnRenderingSpec.fontFamily === \"monospace\") {\n cellStyle.fontFamily = \"Spline Sans Mono\";\n cellStyle.fontWeight = 300;\n } else {\n cellStyle.fontFamily = columnRenderingSpec.fontFamily;\n }\n }\n const headerName =\n readAnnotation(labeledSpec.spec, Annotation.Label)?.trim() ??\n readAnnotation(spec.spec, Annotation.Label)?.trim() ??\n `Unlabeled ${spec.type} ${iCol}`;\n\n return {\n colId,\n mainMenuItems: defaultMainMenuItems,\n context: spec,\n field: `${iCol}`,\n headerName,\n lockPosition: spec.type === \"axis\",\n hide: hiddenColIds !== undefined && hiddenColIds.includes(colId),\n valueFormatter: columnRenderingSpec.valueFormatter,\n headerComponent: PlAgColumnHeader,\n cellRendererSelector: cellButtonAxisParams?.showCellButtonForAxisId\n ? (params: ICellRendererParams) => {\n if (spec.type !== \"axis\") return;\n\n const axisId = (params.colDef?.context as PTableColumnSpec)?.id as AxisId;\n if (isJsonEqual(axisId, cellButtonAxisParams.showCellButtonForAxisId)) {\n return {\n component: PlAgTextAndButtonCell,\n params: {\n invokeRowsOnDoubleClick: cellButtonAxisParams.cellButtonInvokeRowsOnDoubleClick,\n onClick: (params: ICellRendererParams<PlAgDataTableV2Row>) => {\n cellButtonAxisParams.trigger(params.data?.axesKey);\n },\n },\n };\n }\n }\n : undefined,\n cellStyle,\n headerComponentParams: {\n type: ((): PlAgHeaderComponentType => {\n switch (valueType) {\n case ValueType.Int:\n case ValueType.Long:\n case ValueType.Float:\n case ValueType.Double:\n return \"Number\";\n case ValueType.String:\n case ValueType.Bytes:\n return \"Text\";\n default:\n throw Error(`unsupported data type: ${valueType}`);\n }\n })(),\n tooltip:\n readAnnotation(spec.spec, Annotation.Description)?.trim() ??\n readAnnotation(labeledSpec.spec, Annotation.Description)?.trim(),\n info:\n readAnnotation(spec.spec, Annotation.Table.Info)?.trim() ??\n readAnnotation(labeledSpec.spec, Annotation.Table.Info)?.trim(),\n } satisfies PlAgHeaderComponentParams,\n cellDataType: (() => {\n switch (valueType) {\n case ValueType.Int:\n case ValueType.Long:\n case ValueType.Float:\n case ValueType.Double:\n return \"number\";\n case ValueType.String:\n case ValueType.Bytes:\n return \"text\";\n default:\n throw Error(`unsupported data type: ${valueType}`);\n }\n })(),\n };\n}\n\ntype LabelColumnLookup = (axisId: AxisId) => number;\n\n/** Build index mapping from full tableSpecs to their position in visibleTableSpecs (missing → -1). */\nfunction buildSpecsToVisibleSpecsMapping(\n tableSpecs: PTableColumnSpec[],\n visibleTableSpecs: PTableColumnSpec[],\n): Map<number, number> {\n const specId = (spec: PTableColumnSpec) =>\n canonicalizeJson<PTableColumnId>(getPTableColumnId(spec));\n const visibleSpecsMap = new Map(\n visibleTableSpecs.entries().map(([i, spec]) => [specId(spec), i] as const),\n );\n return new Map(\n tableSpecs.entries().map(([i, spec]) => {\n const visibleSpecIdx = visibleSpecsMap.get(specId(spec));\n return [i, isNil(visibleSpecIdx) ? -1 : visibleSpecIdx];\n }),\n );\n}\n\n/** Predicate that returns true when an axis is one of the sheet partition axes. */\nfunction createPartitionedAxisPredicate(sheets: PlDataTableSheet[]): (axisId: AxisId) => boolean {\n const sheetAxesIds = sheets.map((sheet) => getAxisId(sheet.axis));\n return (axisId) => sheetAxesIds.some((id) => matchAxisId(id, axisId));\n}\n\n/**\n * Collect label columns (skipping partitioned axes and duplicates) and return a\n * lookup function that resolves labeled axisId → label column index (or -1).\n */\nfunction collectLabelColumnsByAxis(\n tableSpecs: PTableColumnSpec[],\n isPartitionedAxis: (axisId: AxisId) => boolean,\n): LabelColumnLookup {\n const labelColumns: { axisId: AxisId; labelColumnIdx: number }[] = [];\n for (const [i, spec] of tableSpecs.entries()) {\n if (spec.type !== \"column\" || !isLabelColumnSpec(spec.spec)) continue;\n const labeledAxisId = getAxisId(spec.spec.axesSpec[0]);\n if (isPartitionedAxis(labeledAxisId)) continue;\n if (labelColumns.some((info) => matchAxisId(info.axisId, labeledAxisId))) {\n console.warn(`multiple label columns match axisId: ${JSON.stringify(labeledAxisId)}`);\n continue;\n }\n labelColumns.push({ axisId: labeledAxisId, labelColumnIdx: i });\n }\n return (axisId) =>\n labelColumns.find((info) => matchAxisId(info.axisId, axisId))?.labelColumnIdx ?? -1;\n}\n\n/** Indices of columns to display: drop partitioned axes, label/linker columns, hidden columns. */\nfunction selectDisplayableIndices(\n tableSpecs: PTableColumnSpec[],\n isPartitionedAxis: (axisId: AxisId) => boolean,\n): number[] {\n return tableSpecs\n .entries()\n .filter(([, spec]) => {\n switch (spec.type) {\n case \"axis\":\n return !isColumnHidden(spec.spec) && !isPartitionedAxis(spec.id);\n case \"column\":\n return (\n !isColumnHidden(spec.spec) &&\n !isLabelColumnSpec(spec.spec) &&\n !isLinkerColumnSpec(spec.spec)\n );\n }\n })\n .map(([i]) => i)\n .toArray();\n}\n\n/** Sort: axes first, then columns by OrderPriority annotation (higher priority = further left). */\nfunction sortIndicesByTypeAndPriority(indices: number[], tableSpecs: PTableColumnSpec[]): number[] {\n const priorityOf = (i: number): number => {\n const spec = tableSpecs[i];\n return spec.type === \"column\"\n ? (readAnnotationJson(spec.spec, Annotation.Table.OrderPriority) ?? 0)\n : 0;\n };\n return [...indices].sort((a, b) => {\n if (tableSpecs[a].type !== tableSpecs[b].type) {\n return tableSpecs[a].type === \"axis\" ? -1 : 1;\n }\n return priorityOf(b) - priorityOf(a);\n });\n}\n\n/** For each axis entry substitute the index of its matching label column when one exists. */\nfunction replaceAxesWithLabelColumns(\n fields: number[],\n tableSpecs: PTableColumnSpec[],\n getLabelColumnIndex: LabelColumnLookup,\n): number[] {\n return fields.map((i) => {\n const spec = tableSpecs[i];\n const labelIdx = spec.type === \"axis\" ? getLabelColumnIndex(spec.id) : -1;\n return labelIdx === -1 ? i : labelIdx;\n });\n}\n\n/** Default hidden col ids built from columns marked with the Optional annotation. */\nfunction computeDefaultHiddenColIds(\n fields: number[],\n indices: number[],\n tableSpecs: PTableColumnSpec[],\n): PlTableColumnIdJson[] {\n return fields.reduce<PlTableColumnIdJson[]>((acc, field, i) => {\n const spec = tableSpecs[field];\n if (spec.type !== \"column\" || !isColumnOptional(spec.spec)) return acc;\n const labeledSpec = tableSpecs[indices[i]];\n return [...acc, canonicalizeJson<PlTableColumnId>({ source: spec, labeled: labeledSpec })];\n }, []);\n}\n\n/** Extract axis indices and specs from the visible table (always present as part of join). */\nfunction collectVisibleAxes(\n visibleTableSpecs: PTableColumnSpec[],\n): [number, PTableColumnSpecAxis][] {\n return visibleTableSpecs\n .entries()\n .filter((entry): entry is [number, PTableColumnSpecAxis] => entry[1].type === \"axis\")\n .toArray();\n}\n\n/**\n * Compose request indices for the visible table:\n * non-hidden display fields first, then visible axes (deduplicated).\n * Returns fieldResultMapping (display field → position in requestIndices, -1 if not requested)\n * and axesResultIndices (visible axis → position in requestIndices).\n */\nfunction buildRequestIndices(\n indices: number[],\n visibleAxesIndices: number[],\n specsToVisibleSpecsMapping: Map<number, number>,\n): {\n requestIndices: number[];\n axesResultIndices: number[];\n fieldResultMapping: number[];\n} {\n const resolved = indices.map((displayField) => {\n const idx = specsToVisibleSpecsMapping.get(displayField);\n return isNil(idx) || idx === -1 ? null : idx;\n });\n const requestIndices = uniq([\n ...resolved.filter((v): v is number => v !== null),\n ...visibleAxesIndices,\n ]);\n const fieldResultMapping = resolved.map((v) => (v === null ? -1 : requestIndices.indexOf(v)));\n const axesResultIndices = visibleAxesIndices.map((vi) => requestIndices.indexOf(vi));\n\n return { requestIndices, axesResultIndices, fieldResultMapping };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,
|
|
1
|
+
{"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,QAUb,CARM,EAAA,SAAA,GAAA,EADR,EASE,GAAA;;IAPC,MAAM,EAAA;IACN,kBAAgB;IAChB,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,SAAS,EAAM;IACf,uBAAqB,EAAM;IAC3B,oBAAoB,EAAM;IAC1B,6BAA6B,EAAM"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePlugin.d.ts","sourceRoot":"","sources":["../../src/composition/usePlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAE5C,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,sBAAsB,CAAC;AAE9B,sEAAsE;AACtE,MAAM,WAAW,WAAW,CAC1B,IAAI,GAAG,OAAO,EACd,OAAO,GAAG,OAAO,EACjB,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAElC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;QACvB,IAAI,EAAE,IAAI,CAAC;QACX,OAAO,EAAE,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5C;aAAG,CAAC,IAAI,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS;SAAE,GAChD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5B,YAAY,EAAE,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjD;aAAG,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,EAAE,KAAK;SAAE,GAChC,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,SAAS,CAAC,CAAC;KACvC,CAAC,CAAC;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED,wFAAwF;AACxF,MAAM,WAAW,YAAY;IAC3B,sBAAsB,CAAC,CAAC,SAAS,iBAAiB,EAChD,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GACtB,WAAW,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;CACxF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,iBAAiB,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,uFAW7E"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { pluginDataKey as e } from "
|
|
1
|
+
import { pluginDataKey as e } from "../defineApp.js";
|
|
2
2
|
import { inject as t } from "vue";
|
|
3
|
-
//#region src/usePlugin.ts
|
|
3
|
+
//#region src/composition/usePlugin.ts
|
|
4
4
|
function n(n) {
|
|
5
5
|
let r = t(e);
|
|
6
6
|
if (!r) throw Error("usePlugin requires a V3 block (BlockModelV3). Make sure the block uses apiVersion 3 and the plugin is installed.");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePlugin.js","names":[],"sources":["../../src/composition/usePlugin.ts"],"sourcesContent":["import { inject, type Reactive } from \"vue\";\nimport { pluginDataKey } from \"../defineApp\";\nimport type {\n PluginHandle,\n InferFactoryData,\n InferFactoryOutputs,\n InferFactoryUiServices,\n PluginFactoryLike,\n} from \"@platforma-sdk/model\";\n\n/** Per-plugin reactive model exposed to consumers via usePlugin(). */\nexport interface PluginState<\n Data = unknown,\n Outputs = unknown,\n Services = Record<string, unknown>,\n> {\n readonly model: Reactive<{\n data: Data;\n outputs: Outputs extends Record<string, unknown>\n ? { [K in keyof Outputs]: Outputs[K] | undefined }\n : Record<string, unknown>;\n outputErrors: Outputs extends Record<string, unknown>\n ? { [K in keyof Outputs]?: Error }\n : Record<string, Error | undefined>;\n }>;\n readonly services: Services;\n}\n\n/** Internal interface for plugin access — provided via Vue injection to usePlugin(). */\nexport interface PluginAccess {\n getOrCreatePluginState<F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n ): PluginState<InferFactoryData<F>, InferFactoryOutputs<F>, InferFactoryUiServices<F>>;\n}\n\n/**\n * Composable for accessing a plugin's reactive model: data, outputs, and outputErrors.\n *\n * Mirrors the `app.model` access pattern — `plugin.model.data` is reactive and deep-watched,\n * mutations are automatically queued and sent to storage.\n *\n * @param handle - Opaque plugin handle obtained from `app.plugins`.\n * @typeParam F - The plugin factory type (inferred from the handle)\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { usePlugin, type InferPluginHandle } from '@platforma-sdk/ui-vue';\n * import type { CounterPlugin } from './plugins/counter';\n *\n * const props = defineProps<{ instance: InferPluginHandle<CounterPlugin> }>();\n * const plugin = usePlugin(props.instance);\n *\n * plugin.model.data.count += 1; // reactive, triggers storage update\n * plugin.model.outputs.displayText // computed, plugin's own outputs only\n * plugin.model.outputErrors.displayText // Error | undefined\n * </script>\n * ```\n */\nexport function usePlugin<F extends PluginFactoryLike>(handle: PluginHandle<F>) {\n const access = inject<PluginAccess>(pluginDataKey);\n\n if (!access) {\n throw new Error(\n \"usePlugin requires a V3 block (BlockModelV3). \" +\n \"Make sure the block uses apiVersion 3 and the plugin is installed.\",\n );\n }\n\n return access.getOrCreatePluginState<F>(handle);\n}\n"],"mappings":";;;AA2DA,SAAgB,EAAuC,GAAyB;CAC9E,IAAM,IAAS,EAAqB,EAAc;AAElD,KAAI,CAAC,EACH,OAAU,MACR,mHAED;AAGH,QAAO,EAAO,uBAA0B,EAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useServices.d.ts","sourceRoot":"","sources":["../../src/composition/useServices.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,0DAE1B"}
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import K from "./components/PlAnnotations/components/PlAnnotations.js";
|
|
|
30
30
|
import q from "./components/PlAnnotations/components/PlAnnotationsModal.js";
|
|
31
31
|
import J from "./components/PlBtnExportArchive/PlBtnExportArchive.js";
|
|
32
32
|
import Y from "./components/PlDatasetSelector/PlDatasetSelector.js";
|
|
33
|
-
import { usePlugin as X } from "./usePlugin.js";
|
|
33
|
+
import { usePlugin as X } from "./composition/usePlugin.js";
|
|
34
34
|
import { defineStore as Z } from "./defineStore.js";
|
|
35
35
|
import { activateAgGrid as Q } from "./composition/AgGrid/index.js";
|
|
36
36
|
import { objectHash as $ } from "./objectHash.js";
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Mutable } from '@milaboratories/helpers';
|
|
2
|
-
import { NavigationState, BlockOutputsBase, BlockStateV3, PlatformaV3, ValueWithUTag, AuthorMarker, PlatformaExtended, InferPluginHandles } from '@platforma-sdk/model';
|
|
3
|
-
import { UiServices as AllUiServices } from '@milaboratories/pl-model-common';
|
|
2
|
+
import { NavigationState, BlockOutputsBase, BlockStateV3, PlatformaV3, ValueWithUTag, AuthorMarker, PlatformaExtended, InferPluginHandles, UiServices as AllUiServices } from '@platforma-sdk/model';
|
|
4
3
|
import { OutputValues, OutputErrors, AppSettings } from '../types';
|
|
5
|
-
import { PluginAccess } from '../usePlugin';
|
|
4
|
+
import { PluginAccess } from '../composition/usePlugin';
|
|
6
5
|
export declare const patchPoolingDelay = 150;
|
|
7
6
|
export declare const createNextAuthorMarker: (marker: AuthorMarker | undefined) => AuthorMarker;
|
|
8
7
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createAppV3.d.ts","sourceRoot":"","sources":["../../src/internal/createAppV3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"createAppV3.d.ts","sourceRoot":"","sources":["../../src/internal/createAppV3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAKlB,UAAU,IAAI,aAAa,EAE5B,MAAM,sBAAsB,CAAC;AAW9B,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAMxE,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI1E,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAWrC,eAAO,MAAM,sBAAsB,GAAI,QAAQ,YAAY,GAAG,SAAS,KAAG,YAGxE,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CACzB,IAAI,GAAG,OAAO,EACd,IAAI,GAAG,OAAO,EACd,OAAO,SAAS,gBAAgB,GAAG,gBAAgB,EACnD,IAAI,SAAS,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,EACxC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,UAAU,SAAS,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,EAElE,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EACvD,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,EACzF,QAAQ,EAAE,WAAW;;eAsGZ,MAAM;;;;;;;;qBAvDJ,OAAO,CAAC,OAAO,CAAC;0BACX,OAAO;6BACJ,eAAe,CAAC,IAAI,CAAC;;;;;;;;yBA+IkB,IAAI;oCAEf,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAK3E;;;;;;WAMG;uBACY,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;QAMtD;;;;;WAKG;yBACc,IAAI;;;;EA8HxB;AAED,MAAM,MAAM,SAAS,CACnB,IAAI,GAAG,OAAO,EACd,IAAI,GAAG,OAAO,EACd,OAAO,SAAS,gBAAgB,GAAG,gBAAgB,EACnD,IAAI,SAAS,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,EACxC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,UAAU,SAAS,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,IAChE,UAAU,CAAC,OAAO,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -55,7 +55,7 @@ function C(C, w, T) {
|
|
|
55
55
|
(async () => {
|
|
56
56
|
for (window.addEventListener("beforeunload", () => {
|
|
57
57
|
A.value = !0, w.dispose().then(y).catch((e) => {
|
|
58
|
-
D("error in dispose", e);
|
|
58
|
+
D("platforma error in dispose", e);
|
|
59
59
|
});
|
|
60
60
|
}); !A.value;) try {
|
|
61
61
|
let e = await w.getPatches(j.value).then(y);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createAppV3.js","names":[],"sources":["../../src/internal/createAppV3.ts"],"sourcesContent":["import { deepClone, delay, uniqueId } from \"@milaboratories/helpers\";\nimport type { Mutable } from \"@milaboratories/helpers\";\nimport type {\n NavigationState,\n BlockOutputsBase,\n BlockStateV3,\n PlatformaV3,\n ValueWithUTag,\n AuthorMarker,\n PlatformaExtended,\n InferPluginHandles,\n PluginHandle,\n InferFactoryData,\n InferFactoryOutputs,\n InferFactoryUiServices,\n PluginFactoryLike,\n} from \"@platforma-sdk/model\";\nimport {\n hasAbortError,\n unwrapResult,\n deriveDataFromStorage,\n getPluginData,\n isPluginOutputKey,\n pluginOutputPrefix,\n} from \"@platforma-sdk/model\";\nimport { type UiServices as AllUiServices } from \"@milaboratories/pl-model-common\";\nimport type { Ref } from \"vue\";\nimport { reactive, computed, ref, markRaw } from \"vue\";\nimport type { OutputValues, OutputErrors, AppSettings } from \"../types\";\nimport { parseQuery } from \"../urls\";\nimport { ensureOutputHasStableFlag, MultiError } from \"../utils\";\nimport { applyPatch } from \"fast-json-patch\";\nimport { UpdateSerializer } from \"./UpdateSerializer\";\nimport { watchIgnorable } from \"@vueuse/core\";\nimport type { PluginState, PluginAccess } from \"../usePlugin\";\nimport { logDebug, logError } from \"./utils\";\nimport { getServices } from \"./getServices\";\n\nexport const patchPoolingDelay = 150;\n\n/** Internal per-plugin state with reconciliation support. */\ninterface InternalPluginState<\n Data = unknown,\n Outputs = unknown,\n Services = Record<string, unknown>,\n> extends PluginState<Data, Outputs, Services> {\n readonly ignoreUpdates: (fn: () => void) => void;\n}\n\nexport const createNextAuthorMarker = (marker: AuthorMarker | undefined): AuthorMarker => ({\n authorId: marker?.authorId ?? uniqueId(),\n localVersion: (marker?.localVersion ?? 0) + 1,\n});\n\n/**\n * Creates an application instance with reactive state management, outputs, and methods for state updates and navigation.\n *\n * @template Args - The type of arguments used in the application.\n * @template Outputs - The type of block outputs extending `BlockOutputsBase`.\n * @template Data - The type of the block data.\n * @template Href - The type of navigation href, defaulting to a string starting with `/`.\n *\n * @param state - Initial state of the application, including args, outputs, UI state, and navigation state.\n * @param platforma - A platform interface for interacting with block states.\n * @param settings - Application settings, such as debug flags.\n *\n * @returns A reactive application object with methods, getters, and state.\n */\nexport function createAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n Plugins extends Record<string, unknown> = Record<string, unknown>,\n UiServices extends Partial<AllUiServices> = Partial<AllUiServices>,\n>(\n state: ValueWithUTag<BlockStateV3<Data, Outputs, Href>>,\n platforma: PlatformaExtended<PlatformaV3<Data, Args, Outputs, Href, Plugins, UiServices>>,\n settings: AppSettings,\n) {\n const debug = settings.debug ? logDebug : () => {};\n const error = logError;\n\n const data = {\n isExternalSnapshot: false,\n author: {\n authorId: uniqueId(),\n localVersion: 0,\n },\n };\n\n const nextAuthorMarker = () => {\n data.author = createNextAuthorMarker(data.author);\n debug(\"nextAuthorMarker\", data.author);\n return data.author;\n };\n\n const closedRef = ref(false);\n\n const uTagRef = ref(state.uTag);\n\n const debounceSpan = settings.debounceSpan ?? 200;\n\n const setDataQueue = new UpdateSerializer({ debounceSpan });\n const pluginDataQueues = new Map<PluginHandle, UpdateSerializer>();\n const getPluginDataQueue = (handle: PluginHandle): UpdateSerializer => {\n let queue = pluginDataQueues.get(handle);\n if (!queue) {\n queue = new UpdateSerializer({ debounceSpan });\n pluginDataQueues.set(handle, queue);\n }\n return queue;\n };\n const setNavigationStateQueue = new UpdateSerializer({ debounceSpan });\n\n /** Lazily-created per-plugin reactive states. */\n const pluginStates = new Map<PluginHandle, InternalPluginState>();\n /**\n * Reactive snapshot of the application state, including args, outputs, UI state, and navigation state.\n */\n const snapshot = ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>(state.value) as Ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>;\n\n const updateData = async (value: Data) => {\n return platforma.mutateStorage({ operation: \"update-block-data\", value }, nextAuthorMarker());\n };\n\n const updatePluginData = async (handle: PluginHandle, value: unknown) => {\n return platforma.mutateStorage(\n { operation: \"update-plugin-data\", pluginId: handle, value },\n nextAuthorMarker(),\n );\n };\n\n const setNavigationState = async (state: NavigationState<Href>) => {\n return platforma.setNavigationState(state);\n };\n\n const outputs = computed<OutputValues<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)\n .filter(([k]) => !isPluginOutputKey(k))\n .map(([k, outputWithStatus]) =>\n platforma.blockModelInfo.outputs[k]?.withStatus\n ? [k, ensureOutputHasStableFlag(outputWithStatus)]\n : [\n k,\n outputWithStatus.ok && outputWithStatus.value !== undefined\n ? outputWithStatus.value\n : undefined,\n ],\n );\n return Object.fromEntries(entries);\n });\n\n const outputErrors = computed<OutputErrors<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)\n .filter(([k]) => !isPluginOutputKey(k))\n .map(([k, vOrErr]) => [\n k,\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined,\n ]);\n return Object.fromEntries(entries);\n });\n\n const appModel = reactive({\n apiVersion: 3,\n error: \"\",\n model: {\n data: deepClone(deriveDataFromStorage<Data>(snapshot.value.blockStorage)) as Data,\n outputs,\n outputErrors,\n },\n }) as {\n error: string;\n model: {\n data: Data;\n outputs: OutputValues<Outputs>;\n outputErrors: OutputErrors<Outputs>;\n };\n };\n\n const { ignoreUpdates } = watchIgnorable(\n () => appModel.model,\n (_newData) => {\n const newData = deepClone(_newData);\n debug(\"setDataQueue appModel.model, data\", newData.data);\n setDataQueue.run(() => updateData(newData.data).then(unwrapResult));\n },\n { deep: true },\n );\n\n const updateAppModel = (newData: { data: Data }) => {\n debug(\"updateAppModel\", newData);\n appModel.model.data = deepClone(newData.data) as Data;\n };\n\n (async () => {\n window.addEventListener(\"beforeunload\", () => {\n closedRef.value = true;\n platforma\n .dispose()\n .then(unwrapResult)\n .catch((err) => {\n error(\"error in dispose\", err);\n });\n });\n\n while (!closedRef.value) {\n try {\n const patches = await platforma.getPatches(uTagRef.value).then(unwrapResult);\n\n debug(\"patches.length\", patches.value.length);\n debug(\"uTagRef.value\", uTagRef.value);\n debug(\"patches.uTag\", patches.uTag);\n debug(\"patches.author\", patches.author);\n debug(\"data.author\", data.author);\n\n uTagRef.value = patches.uTag;\n\n if (patches.value.length === 0) {\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n continue;\n }\n\n const isAuthorChanged = data.author?.authorId !== patches.author?.authorId;\n\n // Immutable behavior, apply external changes to the snapshot\n if (isAuthorChanged || data.isExternalSnapshot) {\n debug(\"got external changes, applying them to the snapshot\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value, false, false).newDocument;\n updateAppModel({ data: deriveDataFromStorage<Data>(snapshot.value.blockStorage) });\n // Reconcile plugin data from external source\n for (const [handle, pluginState] of pluginStates) {\n pluginState.ignoreUpdates(() => {\n pluginState.model.data = deepClone(\n getPluginData(snapshot.value.blockStorage, handle),\n );\n });\n }\n data.isExternalSnapshot = isAuthorChanged;\n });\n } else {\n // Mutable behavior\n debug(\"outputs changed\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value).newDocument;\n });\n }\n\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n } catch (err) {\n if (hasAbortError(err)) {\n debug(\"patches loop aborted\");\n closedRef.value = true;\n } else {\n error(\"error in patches loop\", err);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n }\n })();\n\n const cloneData = () => deepClone(appModel.model.data) as Data;\n const cloneNavigationState = () =>\n deepClone(snapshot.value.navigationState) as Mutable<NavigationState<Href>>;\n\n const methods = {\n cloneData,\n cloneNavigationState,\n /**\n * Updates the UI state by applying a callback.\n *\n * @param cb - Callback to modify the current UI state.\n * @returns A promise resolving after the update is applied.\n * @todo Make it mutable since there is already an initial one\n */\n updateData(cb: (data: Data) => Data): Promise<boolean> {\n const newData = cb(cloneData());\n debug(\"updateData\", newData);\n appModel.model.data = newData;\n return setDataQueue.run(() => updateData(newData).then(unwrapResult));\n },\n /**\n * Navigates to a specific href by updating the navigation state.\n *\n * @param href - The target href to navigate to.\n * @returns A promise resolving after the navigation state is updated.\n */\n navigateTo(href: Href) {\n const newState = cloneNavigationState();\n newState.href = href;\n return setNavigationStateQueue.run(() => setNavigationState(newState).then(unwrapResult));\n },\n async allSettled() {\n await delay(0);\n const allQueues = [\n setDataQueue.allSettled(),\n ...Array.from(pluginDataQueues.values()).map((q) => q.allSettled()),\n ];\n await Promise.all(allQueues);\n },\n };\n\n const services = getServices<UiServices>({ platforma });\n\n /** Creates a lazily-cached per-plugin reactive state. */\n const createPluginState = <F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n ): InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>> => {\n const prefix = pluginOutputPrefix(handle);\n\n const pluginOutputs = computed(() => {\n const result: Record<string, unknown> = {};\n for (const [key, outputWithStatus] of Object.entries(\n snapshot.value.outputs as Partial<Readonly<Outputs>>,\n )) {\n if (!key.startsWith(prefix)) continue;\n const outputKey = key.slice(prefix.length);\n if (platforma.blockModelInfo.outputs[key]?.withStatus) {\n result[outputKey] = outputWithStatus\n ? ensureOutputHasStableFlag(outputWithStatus)\n : undefined;\n } else {\n result[outputKey] =\n outputWithStatus.ok && outputWithStatus.value !== undefined\n ? outputWithStatus.value\n : undefined;\n }\n }\n return result;\n });\n\n const pluginOutputErrors = computed(() => {\n const result: Record<string, Error | undefined> = {};\n for (const [key, vOrErr] of Object.entries(\n snapshot.value.outputs as Partial<Readonly<Outputs>>,\n )) {\n if (!key.startsWith(prefix)) continue;\n result[key.slice(prefix.length)] =\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined;\n }\n return result;\n });\n\n const pluginModel = reactive({\n data: deepClone(getPluginData(snapshot.value.blockStorage, handle)),\n outputs: pluginOutputs,\n outputErrors: pluginOutputErrors,\n }) as InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>>[\"model\"];\n\n const { ignoreUpdates } = watchIgnorable(\n () => pluginModel.data,\n (newData) => {\n if (newData === undefined) return;\n debug(\"plugin setData\", handle, newData);\n getPluginDataQueue(handle).run(() =>\n updatePluginData(handle, deepClone(newData)).then(unwrapResult),\n );\n },\n { deep: true },\n );\n\n return {\n model: pluginModel,\n services: markRaw(services),\n ignoreUpdates,\n };\n };\n\n /** Plugin internals — provided via separate injection key, not exposed on useApp(). */\n const pluginAccess: PluginAccess = {\n getOrCreatePluginState<F extends PluginFactoryLike>(handle: PluginHandle<F>) {\n const existing = pluginStates.get(handle);\n if (existing) {\n return existing as unknown as PluginState<\n InferFactoryData<F>,\n InferFactoryOutputs<F>,\n InferFactoryUiServices<F>\n >;\n }\n const state = createPluginState(handle);\n pluginStates.set(handle, state);\n return state as unknown as PluginState<\n InferFactoryData<F>,\n InferFactoryOutputs<F>,\n InferFactoryUiServices<F>\n >;\n },\n };\n\n const plugins = Object.fromEntries(\n platforma.blockModelInfo.pluginIds.map((id) => [id, { handle: id }]),\n ) as InferPluginHandles<Plugins>;\n\n const getters = {\n closedRef,\n snapshot,\n plugins,\n services: markRaw(services),\n queryParams: computed(() => parseQuery<Href>(snapshot.value.navigationState.href as Href)),\n href: computed(() => snapshot.value.navigationState.href),\n hasErrors: computed(() =>\n Object.values(snapshot.value.outputs as Partial<Readonly<Outputs>>).some((v) => !v?.ok),\n ),\n };\n\n const app = Object.assign(reactive(Object.assign(appModel, getters)), methods);\n\n if (settings.debug) {\n // @ts-expect-error (to inspect in console in debug mode)\n globalThis.__block_app__ = app;\n }\n\n return { app, pluginAccess };\n}\n\nexport type BaseAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n Plugins extends Record<string, unknown> = Record<string, unknown>,\n UiServices extends Partial<AllUiServices> = Partial<AllUiServices>,\n> = ReturnType<typeof createAppV3<Data, Args, Outputs, Href, Plugins, UiServices>>[\"app\"];\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createAppV3.js","names":[],"sources":["../../src/internal/createAppV3.ts"],"sourcesContent":["import { deepClone, delay, uniqueId } from \"@milaboratories/helpers\";\nimport type { Mutable } from \"@milaboratories/helpers\";\nimport type {\n NavigationState,\n BlockOutputsBase,\n BlockStateV3,\n PlatformaV3,\n ValueWithUTag,\n AuthorMarker,\n PlatformaExtended,\n InferPluginHandles,\n PluginHandle,\n InferFactoryData,\n InferFactoryOutputs,\n PluginFactoryLike,\n UiServices as AllUiServices,\n InferFactoryUiServices,\n} from \"@platforma-sdk/model\";\nimport {\n hasAbortError,\n unwrapResult,\n deriveDataFromStorage,\n getPluginData,\n isPluginOutputKey,\n pluginOutputPrefix,\n} from \"@platforma-sdk/model\";\nimport type { Ref } from \"vue\";\nimport { reactive, computed, ref, markRaw } from \"vue\";\nimport type { OutputValues, OutputErrors, AppSettings } from \"../types\";\nimport { parseQuery } from \"../urls\";\nimport { ensureOutputHasStableFlag, MultiError } from \"../utils\";\nimport { applyPatch } from \"fast-json-patch\";\nimport { UpdateSerializer } from \"./UpdateSerializer\";\nimport { watchIgnorable } from \"@vueuse/core\";\nimport type { PluginState, PluginAccess } from \"../composition/usePlugin\";\nimport { logDebug, logError } from \"./utils\";\nimport { getServices } from \"./getServices\";\n\nexport const patchPoolingDelay = 150;\n\n/** Internal per-plugin state with reconciliation support. */\ninterface InternalPluginState<\n Data = unknown,\n Outputs = unknown,\n Services = Record<string, unknown>,\n> extends PluginState<Data, Outputs, Services> {\n readonly ignoreUpdates: (fn: () => void) => void;\n}\n\nexport const createNextAuthorMarker = (marker: AuthorMarker | undefined): AuthorMarker => ({\n authorId: marker?.authorId ?? uniqueId(),\n localVersion: (marker?.localVersion ?? 0) + 1,\n});\n\n/**\n * Creates an application instance with reactive state management, outputs, and methods for state updates and navigation.\n *\n * @template Args - The type of arguments used in the application.\n * @template Outputs - The type of block outputs extending `BlockOutputsBase`.\n * @template Data - The type of the block data.\n * @template Href - The type of navigation href, defaulting to a string starting with `/`.\n *\n * @param state - Initial state of the application, including args, outputs, UI state, and navigation state.\n * @param platforma - A platform interface for interacting with block states.\n * @param settings - Application settings, such as debug flags.\n *\n * @returns A reactive application object with methods, getters, and state.\n */\nexport function createAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n Plugins extends Record<string, unknown> = Record<string, unknown>,\n UiServices extends Partial<AllUiServices> = Partial<AllUiServices>,\n>(\n state: ValueWithUTag<BlockStateV3<Data, Outputs, Href>>,\n platforma: PlatformaExtended<PlatformaV3<Data, Args, Outputs, Href, Plugins, UiServices>>,\n settings: AppSettings,\n) {\n const debug = settings.debug ? logDebug : () => {};\n const error = logError;\n\n const data = {\n isExternalSnapshot: false,\n author: {\n authorId: uniqueId(),\n localVersion: 0,\n },\n };\n\n const nextAuthorMarker = () => {\n data.author = createNextAuthorMarker(data.author);\n debug(\"nextAuthorMarker\", data.author);\n return data.author;\n };\n\n const closedRef = ref(false);\n\n const uTagRef = ref(state.uTag);\n\n const debounceSpan = settings.debounceSpan ?? 200;\n\n const setDataQueue = new UpdateSerializer({ debounceSpan });\n const pluginDataQueues = new Map<PluginHandle, UpdateSerializer>();\n const getPluginDataQueue = (handle: PluginHandle): UpdateSerializer => {\n let queue = pluginDataQueues.get(handle);\n if (!queue) {\n queue = new UpdateSerializer({ debounceSpan });\n pluginDataQueues.set(handle, queue);\n }\n return queue;\n };\n const setNavigationStateQueue = new UpdateSerializer({ debounceSpan });\n\n /** Lazily-created per-plugin reactive states. */\n const pluginStates = new Map<PluginHandle, InternalPluginState>();\n /**\n * Reactive snapshot of the application state, including args, outputs, UI state, and navigation state.\n */\n const snapshot = ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>(state.value) as Ref<{\n outputs: Partial<Outputs>;\n blockStorage: unknown;\n navigationState: NavigationState<Href>;\n }>;\n\n const updateData = async (value: Data) => {\n return platforma.mutateStorage({ operation: \"update-block-data\", value }, nextAuthorMarker());\n };\n\n const updatePluginData = async (handle: PluginHandle, value: unknown) => {\n return platforma.mutateStorage(\n { operation: \"update-plugin-data\", pluginId: handle, value },\n nextAuthorMarker(),\n );\n };\n\n const setNavigationState = async (state: NavigationState<Href>) => {\n return platforma.setNavigationState(state);\n };\n\n const outputs = computed<OutputValues<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)\n .filter(([k]) => !isPluginOutputKey(k))\n .map(([k, outputWithStatus]) =>\n platforma.blockModelInfo.outputs[k]?.withStatus\n ? [k, ensureOutputHasStableFlag(outputWithStatus)]\n : [\n k,\n outputWithStatus.ok && outputWithStatus.value !== undefined\n ? outputWithStatus.value\n : undefined,\n ],\n );\n return Object.fromEntries(entries);\n });\n\n const outputErrors = computed<OutputErrors<Outputs>>(() => {\n const entries = Object.entries(snapshot.value.outputs as Partial<Readonly<Outputs>>)\n .filter(([k]) => !isPluginOutputKey(k))\n .map(([k, vOrErr]) => [\n k,\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined,\n ]);\n return Object.fromEntries(entries);\n });\n\n const appModel = reactive({\n apiVersion: 3,\n error: \"\",\n model: {\n data: deepClone(deriveDataFromStorage<Data>(snapshot.value.blockStorage)) as Data,\n outputs,\n outputErrors,\n },\n }) as {\n error: string;\n model: {\n data: Data;\n outputs: OutputValues<Outputs>;\n outputErrors: OutputErrors<Outputs>;\n };\n };\n\n const { ignoreUpdates } = watchIgnorable(\n () => appModel.model,\n (_newData) => {\n const newData = deepClone(_newData);\n debug(\"setDataQueue appModel.model, data\", newData.data);\n setDataQueue.run(() => updateData(newData.data).then(unwrapResult));\n },\n { deep: true },\n );\n\n const updateAppModel = (newData: { data: Data }) => {\n debug(\"updateAppModel\", newData);\n appModel.model.data = deepClone(newData.data) as Data;\n };\n\n (async () => {\n window.addEventListener(\"beforeunload\", () => {\n closedRef.value = true;\n platforma\n .dispose()\n .then(unwrapResult)\n .catch((err) => {\n error(\"platforma error in dispose\", err);\n });\n });\n\n while (!closedRef.value) {\n try {\n const patches = await platforma.getPatches(uTagRef.value).then(unwrapResult);\n\n debug(\"patches.length\", patches.value.length);\n debug(\"uTagRef.value\", uTagRef.value);\n debug(\"patches.uTag\", patches.uTag);\n debug(\"patches.author\", patches.author);\n debug(\"data.author\", data.author);\n\n uTagRef.value = patches.uTag;\n\n if (patches.value.length === 0) {\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n continue;\n }\n\n const isAuthorChanged = data.author?.authorId !== patches.author?.authorId;\n\n // Immutable behavior, apply external changes to the snapshot\n if (isAuthorChanged || data.isExternalSnapshot) {\n debug(\"got external changes, applying them to the snapshot\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value, false, false).newDocument;\n updateAppModel({ data: deriveDataFromStorage<Data>(snapshot.value.blockStorage) });\n // Reconcile plugin data from external source\n for (const [handle, pluginState] of pluginStates) {\n pluginState.ignoreUpdates(() => {\n pluginState.model.data = deepClone(\n getPluginData(snapshot.value.blockStorage, handle),\n );\n });\n }\n data.isExternalSnapshot = isAuthorChanged;\n });\n } else {\n // Mutable behavior\n debug(\"outputs changed\", patches.value);\n ignoreUpdates(() => {\n snapshot.value = applyPatch(snapshot.value, patches.value).newDocument;\n });\n }\n\n await new Promise((resolve) => setTimeout(resolve, patchPoolingDelay));\n } catch (err) {\n if (hasAbortError(err)) {\n debug(\"patches loop aborted\");\n closedRef.value = true;\n } else {\n error(\"error in patches loop\", err);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n }\n })();\n\n const cloneData = () => deepClone(appModel.model.data) as Data;\n const cloneNavigationState = () =>\n deepClone(snapshot.value.navigationState) as Mutable<NavigationState<Href>>;\n\n const methods = {\n cloneData,\n cloneNavigationState,\n /**\n * Updates the UI state by applying a callback.\n *\n * @param cb - Callback to modify the current UI state.\n * @returns A promise resolving after the update is applied.\n * @todo Make it mutable since there is already an initial one\n */\n updateData(cb: (data: Data) => Data): Promise<boolean> {\n const newData = cb(cloneData());\n debug(\"updateData\", newData);\n appModel.model.data = newData;\n return setDataQueue.run(() => updateData(newData).then(unwrapResult));\n },\n /**\n * Navigates to a specific href by updating the navigation state.\n *\n * @param href - The target href to navigate to.\n * @returns A promise resolving after the navigation state is updated.\n */\n navigateTo(href: Href) {\n const newState = cloneNavigationState();\n newState.href = href;\n return setNavigationStateQueue.run(() => setNavigationState(newState).then(unwrapResult));\n },\n async allSettled() {\n await delay(0);\n const allQueues = [\n setDataQueue.allSettled(),\n ...Array.from(pluginDataQueues.values()).map((q) => q.allSettled()),\n ];\n await Promise.all(allQueues);\n },\n };\n\n const services = getServices<UiServices>({ platforma });\n\n /** Creates a lazily-cached per-plugin reactive state. */\n const createPluginState = <F extends PluginFactoryLike>(\n handle: PluginHandle<F>,\n ): InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>> => {\n const prefix = pluginOutputPrefix(handle);\n\n const pluginOutputs = computed(() => {\n const result: Record<string, unknown> = {};\n for (const [key, outputWithStatus] of Object.entries(\n snapshot.value.outputs as Partial<Readonly<Outputs>>,\n )) {\n if (!key.startsWith(prefix)) continue;\n const outputKey = key.slice(prefix.length);\n if (platforma.blockModelInfo.outputs[key]?.withStatus) {\n result[outputKey] = outputWithStatus\n ? ensureOutputHasStableFlag(outputWithStatus)\n : undefined;\n } else {\n result[outputKey] =\n outputWithStatus.ok && outputWithStatus.value !== undefined\n ? outputWithStatus.value\n : undefined;\n }\n }\n return result;\n });\n\n const pluginOutputErrors = computed(() => {\n const result: Record<string, Error | undefined> = {};\n for (const [key, vOrErr] of Object.entries(\n snapshot.value.outputs as Partial<Readonly<Outputs>>,\n )) {\n if (!key.startsWith(prefix)) continue;\n result[key.slice(prefix.length)] =\n vOrErr && vOrErr.ok === false ? new MultiError(vOrErr.errors) : undefined;\n }\n return result;\n });\n\n const pluginModel = reactive({\n data: deepClone(getPluginData(snapshot.value.blockStorage, handle)),\n outputs: pluginOutputs,\n outputErrors: pluginOutputErrors,\n }) as InternalPluginState<InferFactoryData<F>, InferFactoryOutputs<F>>[\"model\"];\n\n const { ignoreUpdates } = watchIgnorable(\n () => pluginModel.data,\n (newData) => {\n if (newData === undefined) return;\n debug(\"plugin setData\", handle, newData);\n getPluginDataQueue(handle).run(() =>\n updatePluginData(handle, deepClone(newData)).then(unwrapResult),\n );\n },\n { deep: true },\n );\n\n return {\n model: pluginModel,\n services: markRaw(services),\n ignoreUpdates,\n };\n };\n\n /** Plugin internals — provided via separate injection key, not exposed on useApp(). */\n const pluginAccess: PluginAccess = {\n getOrCreatePluginState<F extends PluginFactoryLike>(handle: PluginHandle<F>) {\n const existing = pluginStates.get(handle);\n if (existing) {\n return existing as unknown as PluginState<\n InferFactoryData<F>,\n InferFactoryOutputs<F>,\n InferFactoryUiServices<F>\n >;\n }\n const state = createPluginState(handle);\n pluginStates.set(handle, state);\n return state as unknown as PluginState<\n InferFactoryData<F>,\n InferFactoryOutputs<F>,\n InferFactoryUiServices<F>\n >;\n },\n };\n\n const plugins = Object.fromEntries(\n platforma.blockModelInfo.pluginIds.map((id) => [id, { handle: id }]),\n ) as InferPluginHandles<Plugins>;\n\n const getters = {\n closedRef,\n snapshot,\n plugins,\n services: markRaw(services),\n queryParams: computed(() => parseQuery<Href>(snapshot.value.navigationState.href as Href)),\n href: computed(() => snapshot.value.navigationState.href),\n hasErrors: computed(() =>\n Object.values(snapshot.value.outputs as Partial<Readonly<Outputs>>).some((v) => !v?.ok),\n ),\n };\n\n const app = Object.assign(reactive(Object.assign(appModel, getters)), methods);\n\n if (settings.debug) {\n // @ts-expect-error (to inspect in console in debug mode)\n globalThis.__block_app__ = app;\n }\n\n return { app, pluginAccess };\n}\n\nexport type BaseAppV3<\n Data = unknown,\n Args = unknown,\n Outputs extends BlockOutputsBase = BlockOutputsBase,\n Href extends `/${string}` = `/${string}`,\n Plugins extends Record<string, unknown> = Record<string, unknown>,\n UiServices extends Partial<AllUiServices> = Partial<AllUiServices>,\n> = ReturnType<typeof createAppV3<Data, Args, Outputs, Href, Plugins, UiServices>>[\"app\"];\n"],"mappings":"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"}
|
|
@@ -6,5 +6,6 @@ export type UiServiceOptions = {
|
|
|
6
6
|
export declare function createUiServiceRegistry(options: UiServiceOptions): UiServiceRegistry<{
|
|
7
7
|
PFrameSpec: import('@milaboratories/pl-model-common').Branded<"pframeSpec", import('@milaboratories/pl-model-common').ServiceTypesLike<import('@milaboratories/pl-model-common').PFrameSpecDriver, import('@milaboratories/pl-model-common').PFrameSpecDriver, "wasm">>;
|
|
8
8
|
PFrame: import('@milaboratories/pl-model-common').Branded<"pframe", import('@milaboratories/pl-model-common').ServiceTypesLike<import('@milaboratories/pl-model-common').PFrameModelDriver<import('@milaboratories/pl-model-common').PColumn<string | import('@milaboratories/pl-model-common').PColumnValues | import('@milaboratories/pl-model-common').DataInfo<string>>>, import('@milaboratories/pl-model-common').PFrameDriver, "node">>;
|
|
9
|
+
Dialog: import('@milaboratories/pl-model-common').Branded<"dialog", import('@milaboratories/pl-model-common').ServiceTypesLike<Record<string, never>, import('@milaboratories/pl-model-common').DialogService, "main">>;
|
|
9
10
|
}>;
|
|
10
11
|
//# sourceMappingURL=service_factories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service_factories.d.ts","sourceRoot":"","sources":["../../src/internal/service_factories.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAY,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,YAAY,CAAC;CACrB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,gBAAgB
|
|
1
|
+
{"version":3,"file":"service_factories.d.ts","sourceRoot":"","sources":["../../src/internal/service_factories.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAY,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,YAAY,CAAC;CACrB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,gBAAgB;;;;GAMhE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service_factories.js","names":[],"sources":["../../src/internal/service_factories.ts"],"sourcesContent":["/**\n * UI service factories — add a factory for each new service here.\n *\n * Each entry maps a Services key to a factory function that creates the\n * UI-side driver instance:\n * - WASM services: instantiated directly (e.g. SpecDriver)\n * - Node services: proxied via IPC using NodeServiceProxy\n */\n\nimport { Services, UiServiceRegistry } from \"@milaboratories/pl-model-common\";\nimport { SpecDriver } from \"@milaboratories/pf-spec-driver\";\nimport type { ServiceProxy } from \"@platforma-sdk/model\";\n\nexport type UiServiceOptions = {\n proxy: ServiceProxy;\n};\n\nexport function createUiServiceRegistry(options: UiServiceOptions) {\n return new UiServiceRegistry(Services, {\n PFrameSpec: () => new SpecDriver(),\n PFrame: () => options.proxy(Services.PFrame),\n });\n}\n"],"mappings":";;;AAiBA,SAAgB,EAAwB,GAA2B;AACjE,QAAO,IAAI,EAAkB,GAAU;EACrC,kBAAkB,IAAI,GAAY;EAClC,cAAc,EAAQ,MAAM,EAAS,OAAO;EAC7C,CAAC"}
|
|
1
|
+
{"version":3,"file":"service_factories.js","names":[],"sources":["../../src/internal/service_factories.ts"],"sourcesContent":["/**\n * UI service factories — add a factory for each new service here.\n *\n * Each entry maps a Services key to a factory function that creates the\n * UI-side driver instance:\n * - WASM services: instantiated directly (e.g. SpecDriver)\n * - Node services: proxied via IPC using NodeServiceProxy\n */\n\nimport { Services, UiServiceRegistry } from \"@milaboratories/pl-model-common\";\nimport { SpecDriver } from \"@milaboratories/pf-spec-driver\";\nimport type { ServiceProxy } from \"@platforma-sdk/model\";\n\nexport type UiServiceOptions = {\n proxy: ServiceProxy;\n};\n\nexport function createUiServiceRegistry(options: UiServiceOptions) {\n return new UiServiceRegistry(Services, {\n PFrameSpec: () => new SpecDriver(),\n PFrame: () => options.proxy(Services.PFrame),\n Dialog: () => options.proxy(Services.Dialog),\n });\n}\n"],"mappings":";;;AAiBA,SAAgB,EAAwB,GAA2B;AACjE,QAAO,IAAI,EAAkB,GAAU;EACrC,kBAAkB,IAAI,GAAY;EAClC,cAAc,EAAQ,MAAM,EAAS,OAAO;EAC5C,cAAc,EAAQ,MAAM,EAAS,OAAO;EAC7C,CAAC"}
|
package/dist/lib.d.ts
CHANGED
|
@@ -20,8 +20,8 @@ export * from './components/PlBtnExportArchive';
|
|
|
20
20
|
export * from './components/PlAdvancedFilter';
|
|
21
21
|
export * from './components/PlDatasetSelector';
|
|
22
22
|
export * from './defineApp';
|
|
23
|
-
export { usePlugin } from './usePlugin';
|
|
24
|
-
export type { PluginState } from './usePlugin';
|
|
23
|
+
export { usePlugin } from './composition/usePlugin';
|
|
24
|
+
export type { PluginState } from './composition/usePlugin';
|
|
25
25
|
export type { PluginHandle, PluginFactoryLike, InferPluginHandle, InferFactoryData, InferFactoryOutputs, } from '@platforma-sdk/model';
|
|
26
26
|
export * from './createModel';
|
|
27
27
|
export * from './types';
|
package/dist/lib.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gDAAgD,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AAClG,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AAEhG,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,cAAc,aAAa,CAAC;AAE5B,cAAc,+BAA+B,CAAC;AAE9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AAErD,cAAc,4BAA4B,CAAC;AAE3C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,6BAA6B,CAAC;AAE5C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,+BAA+B,CAAC;AAE9C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,aAAa,CAAC;AAE5B,OAAO,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gDAAgD,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AAClG,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AAEhG,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,cAAc,aAAa,CAAC;AAE5B,cAAc,+BAA+B,CAAC;AAE9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AAErD,cAAc,4BAA4B,CAAC;AAE3C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,6BAA6B,CAAC;AAE5C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,+BAA+B,CAAC;AAE9C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,aAAa,CAAC;AAE5B,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAE9B,cAAc,eAAe,CAAC;AAE9B,cAAc,SAAS,CAAC;AAExB,cAAc,eAAe,CAAC;AAE9B,cAAc,sBAAsB,CAAC;AAErC,cAAc,SAAS,CAAC;AAExB,cAAc,cAAc,CAAC;AAE7B,cAAc,kBAAkB,CAAC;AAEjC,cAAc,2BAA2B,CAAC;AAE1C,cAAc,uBAAuB,CAAC;AAEtC,mBAAmB,uBAAuB,CAAC"}
|
package/dist/lib.js
CHANGED
|
@@ -46,7 +46,7 @@ import "./components/PlBtnExportArchive/PlBtnExportArchive.js";
|
|
|
46
46
|
import "./components/PlBtnExportArchive/index.js";
|
|
47
47
|
import "./components/PlDatasetSelector/PlDatasetSelector.js";
|
|
48
48
|
import "./components/PlDatasetSelector/index.js";
|
|
49
|
-
import "./usePlugin.js";
|
|
49
|
+
import "./composition/usePlugin.js";
|
|
50
50
|
import "./defineStore.js";
|
|
51
51
|
import "./composition/AgGrid/index.js";
|
|
52
52
|
import "./objectHash.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/ui-vue",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.68.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"lru-cache": "^11.2.2",
|
|
27
27
|
"vue": "^3.5.24",
|
|
28
28
|
"zod": "~3.25.76",
|
|
29
|
-
"@milaboratories/
|
|
30
|
-
"@milaboratories/
|
|
31
|
-
"@platforma-sdk/model": "1.
|
|
32
|
-
"@milaboratories/
|
|
29
|
+
"@milaboratories/pl-model-common": "1.36.0",
|
|
30
|
+
"@milaboratories/uikit": "2.12.10",
|
|
31
|
+
"@platforma-sdk/model": "1.68.0",
|
|
32
|
+
"@milaboratories/pf-spec-driver": "1.3.4"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@faker-js/faker": "^9.2.0",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"typescript": "~5.9.3",
|
|
46
46
|
"vite": "^8.0.6",
|
|
47
47
|
"vitest": "^4.1.3",
|
|
48
|
-
"@milaboratories/
|
|
48
|
+
"@milaboratories/ts-builder": "1.3.2",
|
|
49
49
|
"@milaboratories/build-configs": "2.0.0",
|
|
50
|
-
"@milaboratories/
|
|
51
|
-
"@milaboratories/ts-
|
|
50
|
+
"@milaboratories/helpers": "1.14.1",
|
|
51
|
+
"@milaboratories/ts-configs": "1.2.3"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"dev": "ts-builder serve --target browser-lib",
|
|
@@ -1,25 +1,38 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { GridApi } from "ag-grid-enterprise";
|
|
3
|
+
import type { PTableHandle } from "@platforma-sdk/model";
|
|
3
4
|
import { PlBtnGhost, usePlBlockPageTitleTeleportTarget } from "@milaboratories/uikit";
|
|
4
5
|
import { shallowRef, toRefs } from "vue";
|
|
5
|
-
import {
|
|
6
|
+
import { isNil } from "es-toolkit";
|
|
7
|
+
import { exportCsv, isCsvExportAvailable } from "./export-csv";
|
|
8
|
+
import type { ExportOptions } from "./export-csv";
|
|
6
9
|
|
|
7
10
|
const props = defineProps<{
|
|
8
11
|
api: GridApi;
|
|
12
|
+
tableHandle?: PTableHandle;
|
|
9
13
|
}>();
|
|
10
14
|
const { api: gridApi } = toRefs(props);
|
|
15
|
+
const csvExportAvailable = isCsvExportAvailable();
|
|
11
16
|
|
|
12
17
|
const exporting = shallowRef(false);
|
|
13
18
|
const initiateExport = () => {
|
|
19
|
+
const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)
|
|
20
|
+
? { tableHandle: props.tableHandle, format: "csv" }
|
|
21
|
+
: undefined;
|
|
22
|
+
|
|
23
|
+
if (isNil(nativeOptions)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
14
27
|
exporting.value = true;
|
|
15
|
-
exportCsv(gridApi.value, () => (exporting.value = false));
|
|
28
|
+
exportCsv(gridApi.value, nativeOptions).finally(() => (exporting.value = false));
|
|
16
29
|
};
|
|
17
30
|
|
|
18
31
|
const teleportTarget = usePlBlockPageTitleTeleportTarget("PlAgCsvExporter");
|
|
19
32
|
</script>
|
|
20
33
|
|
|
21
34
|
<template>
|
|
22
|
-
<Teleport v-if="teleportTarget" :to="teleportTarget">
|
|
35
|
+
<Teleport v-if="teleportTarget && csvExportAvailable" :to="teleportTarget">
|
|
23
36
|
<PlBtnGhost :loading="exporting" icon="export" @click.stop="initiateExport">
|
|
24
37
|
Export
|
|
25
38
|
</PlBtnGhost>
|