synapse-react-client 4.0.20 → 4.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/SWC.index.js +1 -1
  2. package/dist/components/CardContainer/CardConfiguration.d.ts +2 -0
  3. package/dist/components/CardContainer/CardConfiguration.d.ts.map +1 -1
  4. package/dist/components/CardContainer/CardContainer.d.ts.map +1 -1
  5. package/dist/components/CardContainer/CardContainer.js +3 -3
  6. package/dist/components/CardContainer/CardContainer.js.map +1 -1
  7. package/dist/components/CardContainerLogic/CardContainerLogic.d.ts +1 -0
  8. package/dist/components/CardContainerLogic/CardContainerLogic.d.ts.map +1 -1
  9. package/dist/components/CardContainerLogic/CardContainerLogic.js.map +1 -1
  10. package/dist/components/DataExplorer/DataExplorer.css +1 -1
  11. package/dist/components/DataExplorer/DataExplorer.module.js +16 -16
  12. package/dist/components/DataExplorer/DataExplorer.module.js.map +1 -1
  13. package/dist/components/DataExplorer/DataExplorer.module.scss +26 -6
  14. package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.d.ts +5 -3
  15. package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.d.ts.map +1 -1
  16. package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.js +46 -47
  17. package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.js.map +1 -1
  18. package/dist/components/DataGrid/hooks/useColumnResizeHandles.d.ts.map +1 -1
  19. package/dist/components/DataGrid/hooks/useColumnResizeHandles.js +1 -1
  20. package/dist/components/DataGrid/hooks/useColumnResizeHandles.js.map +1 -1
  21. package/dist/components/DataGrid/utils/columnFactory.d.ts.map +1 -1
  22. package/dist/components/DataGrid/utils/columnFactory.js +1 -0
  23. package/dist/components/DataGrid/utils/columnFactory.js.map +1 -1
  24. package/dist/components/GenericCard/GenericCard.d.ts +2 -0
  25. package/dist/components/GenericCard/GenericCard.d.ts.map +1 -1
  26. package/dist/components/GenericCard/GenericCard.js +76 -64
  27. package/dist/components/GenericCard/GenericCard.js.map +1 -1
  28. package/dist/components/GenericCard/TableRowGenericCard.d.ts.map +1 -1
  29. package/dist/components/GenericCard/TableRowGenericCard.js +33 -25
  30. package/dist/components/GenericCard/TableRowGenericCard.js.map +1 -1
  31. package/dist/components/Plot/SynapseSankeyPlot.css +1 -0
  32. package/dist/components/Plot/SynapseSankeyPlot.d.ts +44 -2
  33. package/dist/components/Plot/SynapseSankeyPlot.d.ts.map +1 -1
  34. package/dist/components/Plot/SynapseSankeyPlot.js +343 -38
  35. package/dist/components/Plot/SynapseSankeyPlot.js.map +1 -1
  36. package/dist/components/Plot/SynapseSankeyPlot.module.js +15 -0
  37. package/dist/components/Plot/SynapseSankeyPlot.module.js.map +1 -0
  38. package/dist/components/Plot/SynapseSankeyPlot.module.scss +63 -0
  39. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.d.ts +13 -12
  40. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.d.ts.map +1 -1
  41. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js +88 -77
  42. package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js.map +1 -1
  43. package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.d.ts.map +1 -1
  44. package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.js +63 -74
  45. package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.js.map +1 -1
  46. package/dist/components/TableColumnSchemaEditor/ColumnModelForm.d.ts.map +1 -1
  47. package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js +72 -68
  48. package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
  49. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts +27 -1
  50. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts.map +1 -1
  51. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.js +47 -36
  52. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.js.map +1 -1
  53. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js +1 -1
  54. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
  55. package/dist/components/TableColumnSchemaEditor/TableColumnSchemaFormReducer.d.ts +12 -12
  56. package/dist/components/TableColumnSchemaEditor/Validators/BooleanSchema.d.ts +4 -1
  57. package/dist/components/TableColumnSchemaEditor/Validators/BooleanSchema.d.ts.map +1 -1
  58. package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.d.ts +167 -517
  59. package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.d.ts.map +1 -1
  60. package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.js +65 -65
  61. package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.js.map +1 -1
  62. package/dist/components/TableColumnSchemaEditor/Validators/DatetimeSchema.d.ts +1 -1
  63. package/dist/components/TableColumnSchemaEditor/Validators/DatetimeSchema.d.ts.map +1 -1
  64. package/dist/components/TableColumnSchemaEditor/Validators/DoubleSchema.d.ts +1 -1
  65. package/dist/components/TableColumnSchemaEditor/Validators/DoubleSchema.d.ts.map +1 -1
  66. package/dist/components/TableColumnSchemaEditor/Validators/DoubleSchema.js +6 -13
  67. package/dist/components/TableColumnSchemaEditor/Validators/DoubleSchema.js.map +1 -1
  68. package/dist/components/TableColumnSchemaEditor/Validators/EntityIdSchema.d.ts +1 -1
  69. package/dist/components/TableColumnSchemaEditor/Validators/EntityIdSchema.d.ts.map +1 -1
  70. package/dist/components/TableColumnSchemaEditor/Validators/IntegerSchema.d.ts +1 -1
  71. package/dist/components/TableColumnSchemaEditor/Validators/IntegerSchema.d.ts.map +1 -1
  72. package/dist/components/TableColumnSchemaEditor/Validators/IntegerSchema.js +2 -2
  73. package/dist/components/TableColumnSchemaEditor/Validators/IntegerSchema.js.map +1 -1
  74. package/dist/components/TableColumnSchemaEditor/Validators/OptionalStringSchema.d.ts +1 -1
  75. package/dist/components/TableColumnSchemaEditor/Validators/OptionalStringSchema.d.ts.map +1 -1
  76. package/dist/components/TableColumnSchemaEditor/Validators/getZodSchemaForColumnType.d.ts +2 -2
  77. package/dist/components/TableColumnSchemaEditor/Validators/getZodSchemaForColumnType.d.ts.map +1 -1
  78. package/dist/components/TableColumnSchemaEditor/Validators/getZodSchemaForColumnType.js +15 -16
  79. package/dist/components/TableColumnSchemaEditor/Validators/getZodSchemaForColumnType.js.map +1 -1
  80. package/dist/mocks/mockSearchQueryData.js +2 -2
  81. package/dist/mocks/mockSearchQueryData.js.map +1 -1
  82. package/dist/mocks/msw/handlers/searchQueryHandlers.d.ts +1 -1
  83. package/dist/mocks/msw/handlers/searchQueryHandlers.d.ts.map +1 -1
  84. package/dist/mocks/msw/handlers/searchQueryHandlers.js +6 -3
  85. package/dist/mocks/msw/handlers/searchQueryHandlers.js.map +1 -1
  86. package/dist/mocks/query/mockUserCardTableQueryResultBundle.d.ts +13 -0
  87. package/dist/mocks/query/mockUserCardTableQueryResultBundle.d.ts.map +1 -1
  88. package/dist/mocks/query/mockUserCardTableQueryResultBundle.js +27 -0
  89. package/dist/mocks/query/mockUserCardTableQueryResultBundle.js.map +1 -1
  90. package/dist/style/components/_cards.scss +10 -0
  91. package/dist/style/components/_data-grid-extra.css +1 -1
  92. package/dist/style/components/_data-grid-extra.scss +7 -1
  93. package/dist/style/main.css +1 -1
  94. package/dist/synapse-client/SynapseClient.d.ts.map +1 -1
  95. package/dist/synapse-client/SynapseClient.js +497 -495
  96. package/dist/synapse-client/SynapseClient.js.map +1 -1
  97. package/dist/tsconfig.build.tsbuildinfo +1 -1
  98. package/package.json +7 -5
@@ -1 +1 @@
1
- {"version":3,"file":"SynapseSankeyPlot.js","names":[],"sources":["../../../src/components/Plot/SynapseSankeyPlot.tsx"],"sourcesContent":["import React from 'react'\nimport { useGetFullTableQueryResults } from '@/synapse-queries'\nimport { SynapseConstants } from '@/utils'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions/SqlFunctions'\nimport { Skeleton } from '@mui/material'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport type { Data, Layout, SankeyData } from 'plotly.js'\nimport { PlotFullBundle } from './Plot'\n\nexport type SynapseSankeyPlotProps = {\n /** SQL query whose first column provides node labels and second column provides link values */\n sql: string\n /** Label for the root node that links to every row returned by the query */\n rootLabel: string\n /** Optional plot title */\n title?: string\n}\n\nexport const SynapseSankeyPlot = (\n props: SynapseSankeyPlotProps,\n): React.ReactNode => {\n const { sql, rootLabel, title } = props\n\n const queryRequest: QueryBundleRequest = {\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n partMask: SynapseConstants.BUNDLE_MASK_QUERY_RESULTS,\n entityId: parseEntityIdFromSqlStatement(sql),\n query: {\n sql,\n },\n }\n\n const { data: queryData, isLoading } =\n useGetFullTableQueryResults(queryRequest)\n\n if (isLoading) {\n return <Skeleton width={'100%'} height={'500px'} />\n }\n if (!queryData) {\n return <></>\n }\n\n const rows = queryData.queryResult?.queryResults.rows ?? []\n if (rows.length === 0) {\n return <></>\n }\n\n // Build Sankey nodes and links.\n // Node 0: rootLabel (the shared source node)\n // Nodes 1..N: the label from column 0 of each query row (target nodes)\n const sources: number[] = []\n const targets: number[] = []\n const values: number[] = []\n\n rows.forEach((row, index) => {\n values.push(Number(row.values[1] ?? 0))\n sources.push(0)\n targets.push(index + 1)\n })\n\n const total = values.reduce((sum, v) => sum + v, 0)\n\n // Plotly Sankey processes <br> via convertToTspans(), rendering the count on a second line.\n const nodeLabels: string[] = [`${rootLabel}<br>n=${total}`]\n rows.forEach(row => {\n const label = row.values[0] ?? ''\n const value = Number(row.values[1] ?? 0)\n nodeLabels.push(`${label}<br>n=${value}`)\n })\n\n const sankeyData: Partial<SankeyData>[] = [\n {\n type: 'sankey',\n node: {\n label: nodeLabels,\n },\n link: {\n source: sources,\n target: targets,\n value: values,\n },\n },\n ]\n\n const layout: Partial<Layout> = {\n title,\n }\n\n return (\n <PlotFullBundle\n style={{ width: '100%', height: '450px' }}\n layout={layout}\n data={sankeyData as Data[]}\n config={{ displayModeBar: false }}\n />\n )\n}\n\nexport default SynapseSankeyPlot\n"],"mappings":";;;;;;;;;;AAkBA,IAAa,KACX,MACoB;CACpB,IAAM,EAAE,QAAK,cAAW,aAAU,GAW5B,EAAE,MAAM,GAAW,iBACvB,EAA4B;EAT5B,cAAc;EACd,UAAU;EACV,UAAU,EAA8B,CAAG;EAC3C,OAAO,EACL,OACF;CAI4B,CAAY;CAE1C,IAAI,GACF,OAAO,kBAAC,GAAD;EAAU,OAAO;EAAQ,QAAQ;CAAU,CAAA;CAEpD,IAAI,CAAC,GACH,OAAO,kBAAA,GAAA,CAAI,CAAA;CAGb,IAAM,IAAO,EAAU,aAAa,aAAa,QAAQ,CAAC;CAC1D,IAAI,EAAK,WAAW,GAClB,OAAO,kBAAA,GAAA,CAAI,CAAA;CAMb,IAAM,IAAoB,CAAC,GACrB,IAAoB,CAAC,GACrB,IAAmB,CAAC;CAE1B,EAAK,SAAS,GAAK,MAAU;EAG3B,AAFA,EAAO,KAAK,OAAO,EAAI,OAAO,MAAM,CAAC,CAAC,GACtC,EAAQ,KAAK,CAAC,GACd,EAAQ,KAAK,IAAQ,CAAC;CACxB,CAAC;CAKD,IAAM,IAAuB,CAAC,GAAG,EAAU,QAH7B,EAAO,QAAQ,GAAK,MAAM,IAAM,GAAG,CAGE,GAAO;CAyB1D,OAxBA,EAAK,SAAQ,MAAO;EAClB,IAAM,IAAQ,EAAI,OAAO,MAAM,IACzB,IAAQ,OAAO,EAAI,OAAO,MAAM,CAAC;EACvC,EAAW,KAAK,GAAG,EAAM,QAAQ,GAAO;CAC1C,CAAC,GAqBC,kBAAC,GAAD;EACE,OAAO;GAAE,OAAO;GAAQ,QAAQ;EAAQ;EAChC,QAAA,EANV,SAMU;EACR,MAAM,CArBR;GACE,MAAM;GACN,MAAM,EACJ,OAAO,EACT;GACA,MAAM;IACJ,QAAQ;IACR,QAAQ;IACR,OAAO;GACT;EACF,CAWQ;EACN,QAAQ,EAAE,gBAAgB,GAAM;CACjC,CAAA;AAEL"}
1
+ {"version":3,"file":"SynapseSankeyPlot.js","names":[],"sources":["../../../src/components/Plot/SynapseSankeyPlot.tsx"],"sourcesContent":["import React, { useEffect, useId, useMemo, useRef, useState } from 'react'\nimport { useGetFullTableQueryResults } from '@/synapse-queries'\nimport { SynapseConstants } from '@/utils'\nimport { parseEntityIdFromSqlStatement } from '@/utils/functions/SqlFunctions'\nimport { Skeleton, useTheme } from '@mui/material'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport {\n sankey as d3Sankey,\n sankeyLinkHorizontal,\n type SankeyNode as D3SankeyNode,\n} from 'd3-sankey'\nimport tinycolor from 'tinycolor2'\nimport classNames from 'classnames'\nimport styles from './SynapseSankeyPlot.module.scss'\n\nexport type SynapseSankeyPlotProps = {\n /** SQL query providing the node labels and link values (see labelColumn/valueColumn) */\n sql: string\n /** Label for the left end node that links to every row returned by the query */\n rootLabel: string\n /** Optional plot title */\n title?: string\n /**\n * Column supplying each category's label. Either a column name (matched\n * against the query result headers) or a zero-based index. Defaults to the\n * first column.\n */\n labelColumn?: string | number\n /**\n * Column supplying each link's value. Either a column name or a zero-based\n * index. Defaults to the second column.\n */\n valueColumn?: string | number\n /**\n * Noun for the left end total caption, e.g. \"datasets\" renders\n * \"datasets total\". Defaults to \"items\".\n */\n unitLabel?: string\n /**\n * Phrase describing the breakdown, used in the chart's accessible label,\n * e.g. \"by source\" renders \"All Datasets broken down by source\".\n */\n breakdownLabel?: string\n /**\n * Invoked with a category's label when its left flow, center node, or label\n * is clicked. When provided, those become interactive (pointer cursor).\n */\n onCategoryClick?: (categoryLabel: string) => void\n /** Invoked when the left end node (rootLabel) is clicked. */\n onRootClick?: () => void\n /**\n * Enables \"butterfly\" mode: a second value per category drawn as a mirrored\n * flow from each center node to a right end node. Either a column name or a\n * zero-based index (defaults to the third column when a right end is shown).\n */\n rightValueColumn?: string | number\n /** Label for the right end node (butterfly mode). Defaults to \"Files\". */\n rightLabel?: string\n /** Noun for the right end total caption, e.g. \"files\". Defaults to \"items\". */\n rightUnitLabel?: string\n /** Invoked with a category's label when its right flow is clicked. */\n onRightCategoryClick?: (categoryLabel: string) => void\n /** Invoked when the right end node (rightLabel) is clicked. */\n onRightEndClick?: () => void\n}\n\n// Datum shapes for the d3-sankey graph.\ntype NodeKind = 'leftEnd' | 'source' | 'rightEnd'\ntype NodeDatum = {\n name: string\n value: number\n color: string\n kind: NodeKind\n // Raw per-source counts, used by the butterfly center labels.\n leftValue?: number\n rightValue?: number\n}\ntype LinkDatum = {\n value: number\n // Zero-based index of the center (source) node this link belongs to.\n sourceIndex: number\n side: 'left' | 'right'\n}\ntype LaidOutNode = D3SankeyNode<NodeDatum, LinkDatum>\ntype InteractiveProps = { cursor?: 'pointer'; onClick?: () => void }\n\n// Coordinate space of the SVG. The rendered width is capped at VIEW_W (see the\n// wrapper's maxWidth) so one viewBox unit ≈ one CSS pixel and text renders at\n// its intended size instead of being magnified on wide containers. Generous\n// gutters leave unclipped room for the end figures and labels. The height grows\n// with the number of categories so rows stay legible.\nconst VIEW_W = 920\nconst GUTTER_LEFT = 124\nconst GUTTER_RIGHT = 286\nconst GUTTER_Y = 22\nconst NODE_WIDTH = 13\nconst NODE_PADDING = 34\nconst ROW_HEIGHT = 46\n// Horizontal gap between a node and its adjacent label/figure.\nconst LABEL_GAP = 14\n// Category row: a fixed-width column reserved for the count, so the share\n// micro-bar always starts at the same x regardless of the number's length.\nconst COUNT_COLUMN_W = 70\nconst BAR_TRACK_W = 64\nconst BAR_HEIGHT = 4.5\n// Butterfly mode needs more vertical room per row for the center labels, which\n// sit in the padding gap above each node. The left/right gutters are equal so\n// the center column lands at the SVG's horizontal center (aligning the center\n// labels with the centered title), with room for an end figure on each side.\nconst BUTTERFLY_ROW_HEIGHT = 64\nconst BUTTERFLY_NODE_PADDING = 56\nconst BUTTERFLY_GUTTER_TOP = 44\nconst BUTTERFLY_GUTTER_X = 160\n\nconst midY = (node: LaidOutNode) => ((node.y0 ?? 0) + (node.y1 ?? 0)) / 2\nconst midX = (node: LaidOutNode) => ((node.x0 ?? 0) + (node.x1 ?? 0)) / 2\n\n// The editorial figure beside an end node: an eyebrow label, the total, and a\n// caption (e.g. \"datasets total\"). Mirrored for the right end.\nfunction SankeyEndFigure(props: {\n node: LaidOutNode\n total: number\n unitLabel: string\n align: 'left' | 'right'\n onMouseEnter: () => void\n interactiveProps: InteractiveProps\n}): React.ReactNode {\n const { node, total, unitLabel, align, onMouseEnter, interactiveProps } =\n props\n const theme = useTheme()\n const cy = midY(node)\n const x =\n align === 'left' ? (node.x0 ?? 0) - LABEL_GAP : (node.x1 ?? 0) + LABEL_GAP\n const textAnchor = align === 'left' ? 'end' : 'start'\n return (\n <g onMouseEnter={onMouseEnter} {...interactiveProps}>\n <text\n x={x}\n y={cy - 22}\n textAnchor={textAnchor}\n fontSize={10}\n fontWeight={600}\n letterSpacing={1.2}\n fill={theme.palette.grey[700]}\n >\n {node.name.toUpperCase()}\n </text>\n <text\n x={x}\n y={cy + 6}\n textAnchor={textAnchor}\n fontSize={26}\n fontWeight={600}\n fill={theme.palette.primary.dark}\n className={styles.tabularNums}\n >\n {total.toLocaleString()}\n </text>\n <text\n x={x}\n y={cy + 23}\n textAnchor={textAnchor}\n fontSize={11}\n fontWeight={500}\n fill={theme.palette.text.secondary}\n >\n {`${unitLabel} total`}\n </text>\n </g>\n )\n}\n\n// Hub-and-spoke category label (single value): name, count, share bar, percent,\n// placed to the right of the center node.\nfunction SankeyCategoryLabel(props: {\n node: LaidOutNode\n total: number\n opacity: number\n onMouseEnter: () => void\n interactiveProps: InteractiveProps\n}): React.ReactNode {\n const { node, total, opacity, onMouseEnter, interactiveProps } = props\n const theme = useTheme()\n const cy = midY(node)\n const x = (node.x1 ?? 0) + LABEL_GAP\n const value = node.value ?? 0\n const pct = total > 0 ? value / total : 0\n const barX = x + COUNT_COLUMN_W\n const barY = cy + 6\n return (\n <g\n opacity={opacity}\n className={styles.categoryLabel}\n onMouseEnter={onMouseEnter}\n {...interactiveProps}\n >\n <text\n x={x}\n y={cy - 4}\n fontSize={13}\n fontWeight={600}\n fill={theme.palette.text.primary}\n >\n {node.name}\n </text>\n <text\n x={x}\n y={cy + 14}\n fontSize={13}\n fontWeight={600}\n fill={node.color}\n className={styles.tabularNums}\n >\n {value.toLocaleString()}\n </text>\n <rect\n x={barX}\n y={barY}\n width={BAR_TRACK_W}\n height={BAR_HEIGHT}\n rx={BAR_HEIGHT / 2}\n fill={theme.palette.grey[300]}\n />\n <rect\n x={barX}\n y={barY}\n width={BAR_TRACK_W * pct}\n height={BAR_HEIGHT}\n rx={BAR_HEIGHT / 2}\n fill={node.color}\n />\n <text\n x={barX + BAR_TRACK_W + 7}\n y={cy + 13}\n fontSize={11}\n fontWeight={500}\n fill={theme.palette.grey[700]}\n className={styles.tabularNums}\n >\n {(pct * 100).toFixed(1)}%\n </text>\n </g>\n )\n}\n\n// Butterfly center label: the source name and both counts, centered above the\n// node (the only clear space between the left and right flows).\nfunction SankeyCenterLabel(props: {\n node: LaidOutNode\n leftValue: number\n rightValue: number\n unitLabel: string\n rightUnitLabel: string\n opacity: number\n onMouseEnter: () => void\n interactiveProps: InteractiveProps\n}): React.ReactNode {\n const {\n node,\n leftValue,\n rightValue,\n unitLabel,\n rightUnitLabel,\n opacity,\n onMouseEnter,\n interactiveProps,\n } = props\n const theme = useTheme()\n const cx = midX(node)\n const topY = node.y0 ?? 0\n return (\n <g\n opacity={opacity}\n className={styles.categoryLabel}\n onMouseEnter={onMouseEnter}\n {...interactiveProps}\n >\n <text\n x={cx}\n y={topY - 20}\n textAnchor=\"middle\"\n fontSize={13}\n fontWeight={600}\n fill={theme.palette.text.primary}\n stroke={theme.palette.background.paper}\n className={styles.haloText}\n >\n {node.name}\n </text>\n <text\n x={cx}\n y={topY - 6}\n textAnchor=\"middle\"\n fontSize={11}\n fontWeight={600}\n fill={theme.palette.text.secondary}\n stroke={theme.palette.background.paper}\n className={classNames(styles.tabularNums, styles.haloText)}\n >\n {`${leftValue.toLocaleString()} ${unitLabel} · ${rightValue.toLocaleString()} ${rightUnitLabel}`}\n </text>\n </g>\n )\n}\n\nexport const SynapseSankeyPlot = (\n props: SynapseSankeyPlotProps,\n): React.ReactNode => {\n const {\n sql,\n rootLabel,\n title,\n labelColumn,\n valueColumn,\n unitLabel = 'items',\n breakdownLabel,\n onCategoryClick,\n onRootClick,\n rightValueColumn,\n rightLabel = 'Files',\n rightUnitLabel = 'items',\n onRightCategoryClick,\n onRightEndClick,\n } = props\n const theme = useTheme()\n const gradientPrefix = useId()\n\n const hasRightFlow = rightValueColumn !== undefined\n\n // Index of the center node currently focused (null = nothing focused). Drives\n // the focus/dim hover interaction; shared by both flows of a source.\n const [hovered, setHovered] = useState<number | null>(null)\n // Index of the center node that was clicked; briefly emphasized before the\n // handler fires.\n const [clicked, setClicked] = useState<number | null>(null)\n // One-time gentle fade-in on mount.\n const [visible, setVisible] = useState(false)\n useEffect(() => {\n const id = requestAnimationFrame(() => setVisible(true))\n return () => cancelAnimationFrame(id)\n }, [])\n // Timer that briefly emphasizes a clicked flow before invoking the handler.\n // Held in a ref so it can be cleared on unmount and replaced on rapid clicks.\n const clickTimer = useRef<number | undefined>(undefined)\n useEffect(() => {\n return () => {\n if (clickTimer.current !== undefined) {\n window.clearTimeout(clickTimer.current)\n }\n }\n }, [])\n\n const queryRequest: QueryBundleRequest = {\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n partMask: SynapseConstants.BUNDLE_MASK_QUERY_RESULTS,\n entityId: parseEntityIdFromSqlStatement(sql),\n query: {\n sql,\n },\n }\n\n const { data: queryData, isLoading } =\n useGetFullTableQueryResults(queryRequest)\n\n const rows = useMemo(\n () => queryData?.queryResult?.queryResults.rows ?? [],\n [queryData],\n )\n\n // Resolve the label/value columns (by name or index) against the result\n // headers, falling back to the first columns.\n const { labelIndex, valueIndex, rightValueIndex } = useMemo(() => {\n const headers = queryData?.queryResult?.queryResults.headers ?? []\n const resolve = (col: string | number | undefined, fallback: number) => {\n if (typeof col === 'number') {\n return col\n }\n if (typeof col === 'string') {\n const idx = headers.findIndex(h => h.name === col)\n return idx >= 0 ? idx : fallback\n }\n return fallback\n }\n return {\n labelIndex: resolve(labelColumn, 0),\n valueIndex: resolve(valueColumn, 1),\n rightValueIndex: hasRightFlow ? resolve(rightValueColumn, 2) : -1,\n }\n }, [queryData, labelColumn, valueColumn, rightValueColumn, hasRightFlow])\n\n // Theme-derived palette: end nodes use the dark primary color; category nodes\n // step through a light-to-dark sweep of the primary color so they stay\n // on-brand while remaining distinguishable (even when a portal's primary and\n // secondary colors are identical).\n const fontFamily = theme.typography.fontFamily ?? 'inherit'\n const endColor = theme.palette.primary.dark\n const textColor = theme.palette.text.primary\n\n // viewH feeds the SVG viewBox, so it lives at component scope; the remaining\n // spacing is derived inside the layout memo below.\n const gutterTop = hasRightFlow ? BUTTERFLY_GUTTER_TOP : GUTTER_Y\n const rowHeight = hasRightFlow ? BUTTERFLY_ROW_HEIGHT : ROW_HEIGHT\n const viewH = Math.max(320, gutterTop + GUTTER_Y + rows.length * rowHeight)\n\n // Build and lay out the graph. Memoized so hovering (which only changes\n // opacity) doesn't recompute the layout.\n const graphResult = useMemo(() => {\n if (rows.length === 0) {\n return null\n }\n const gradientStart = tinycolor(theme.palette.primary.main).lighten(18)\n const gradientEnd = tinycolor(theme.palette.primary.main).darken(12)\n const categoryColor = (index: number) =>\n rows.length <= 1\n ? theme.palette.primary.main\n : tinycolor\n .mix(gradientStart, gradientEnd, (index / (rows.length - 1)) * 100)\n .toHexString()\n\n const sources = rows.map((row, index) => ({\n name: String(row.values[labelIndex] ?? ''),\n leftValue: Number(row.values[valueIndex] ?? 0),\n rightValue: hasRightFlow ? Number(row.values[rightValueIndex] ?? 0) : 0,\n color: categoryColor(index),\n }))\n const totalLeft = sources.reduce((sum, s) => sum + s.leftValue, 0)\n const totalRight = sources.reduce((sum, s) => sum + s.rightValue, 0)\n const rightEndIndex = sources.length + 1\n\n // d3-sankey scales every ribbon by a single value→thickness factor. When the\n // two flows differ in magnitude (e.g. ~25 datasets vs thousands of files),\n // the smaller side collapses to hairlines. Scale the left flow so both\n // halves sum to the same total — ribbon widths then read as each side's\n // share. The real counts are preserved on the node data for the labels.\n const leftScale =\n hasRightFlow && totalLeft > 0 && totalRight > 0\n ? totalRight / totalLeft\n : 1\n const linkValue = (value: number, side: 'left' | 'right') =>\n side === 'left' ? value * leftScale : value\n\n const nodes: NodeDatum[] = [\n { name: rootLabel, value: totalLeft, color: endColor, kind: 'leftEnd' },\n ...sources.map(s => ({\n name: s.name,\n value: s.leftValue,\n color: s.color,\n kind: 'source' as const,\n leftValue: s.leftValue,\n rightValue: s.rightValue,\n })),\n ...(hasRightFlow\n ? [\n {\n name: rightLabel,\n value: totalRight,\n color: endColor,\n kind: 'rightEnd' as const,\n },\n ]\n : []),\n ]\n const links: ({ source: number; target: number } & LinkDatum)[] = [\n ...sources.map((s, index) => ({\n source: 0,\n target: index + 1,\n value: linkValue(s.leftValue, 'left'),\n sourceIndex: index,\n side: 'left' as const,\n })),\n ...(hasRightFlow\n ? sources.map((s, index) => ({\n source: index + 1,\n target: rightEndIndex,\n value: linkValue(s.rightValue, 'right'),\n sourceIndex: index,\n side: 'right' as const,\n }))\n : []),\n ]\n\n const nodePadding = hasRightFlow ? BUTTERFLY_NODE_PADDING : NODE_PADDING\n // Symmetric gutters in butterfly mode center the column layout.\n const gutterLeft = hasRightFlow ? BUTTERFLY_GUTTER_X : GUTTER_LEFT\n const gutterRight = hasRightFlow ? BUTTERFLY_GUTTER_X : GUTTER_RIGHT\n const layout = d3Sankey<NodeDatum, LinkDatum>()\n .nodeWidth(NODE_WIDTH)\n .nodePadding(nodePadding)\n .nodeSort(null) // preserve query order top-to-bottom\n .extent([\n [gutterLeft, gutterTop],\n [VIEW_W - gutterRight, viewH - GUTTER_Y],\n ])\n\n return {\n graph: layout({\n nodes: nodes.map(d => ({ ...d })),\n links: links.map(d => ({ ...d })),\n }),\n // Real (unscaled) totals for the end-node figures.\n totalLeft,\n totalRight,\n }\n }, [\n rows,\n labelIndex,\n valueIndex,\n rightValueIndex,\n hasRightFlow,\n rootLabel,\n rightLabel,\n endColor,\n theme.palette.primary.main,\n viewH,\n gutterTop,\n ])\n\n if (isLoading) {\n return <Skeleton width={'100%'} height={'500px'} />\n }\n if (!graphResult) {\n return <></>\n }\n\n const { graph, totalLeft, totalRight } = graphResult\n const linkPath = sankeyLinkHorizontal<NodeDatum, LinkDatum>()\n\n // The clicked flow takes precedence over the hovered one for emphasis.\n const focusIndex = clicked ?? hovered\n // Dim the rest harder once a selection has been committed.\n const dimLink = clicked !== null ? 0.05 : 0.07\n const dimNode = clicked !== null ? 0.1 : 0.16\n const dimLabel = clicked !== null ? 0.15 : 0.32\n\n // Opacity helpers for the focus/dim interaction. Both flows of a focused\n // source share its center-node index.\n const linkOpacity = (sourceIndex: number) =>\n focusIndex === null\n ? 0.6\n : sourceIndex === focusIndex\n ? clicked !== null\n ? 1\n : 0.95\n : dimLink\n const nodeOpacity = (node: LaidOutNode) =>\n focusIndex === null ||\n node.kind !== 'source' ||\n (node.index ?? 1) - 1 === focusIndex\n ? 1\n : dimNode\n const labelOpacity = (sourceIndex: number) =>\n focusIndex === null || focusIndex === sourceIndex ? 1 : dimLabel\n\n // Clicking a center flow briefly emphasizes it (a quick \"swell\") and then\n // fires the handler, so the navigation feels intentional. No tabIndex/role:\n // those make the browser draw a focus outline box around the SVG shape.\n const activate = (sourceIndex: number, fire: () => void) => {\n if (clickTimer.current !== undefined) {\n window.clearTimeout(clickTimer.current)\n }\n setClicked(sourceIndex)\n clickTimer.current = window.setTimeout(() => {\n clickTimer.current = undefined\n // Clear the transient emphasis before invoking the handler so the chart\n // returns to its resting state for consumers whose handler doesn't\n // navigate away (and unmount) the component.\n setClicked(null)\n fire()\n }, 320)\n }\n // Center flows swell on click; end nodes navigate immediately.\n const flowProps = (\n sourceIndex: number,\n fire: (() => void) | undefined,\n ): InteractiveProps =>\n fire\n ? { cursor: 'pointer', onClick: () => activate(sourceIndex, fire) }\n : {}\n const endProps = (fire: (() => void) | undefined): InteractiveProps =>\n fire ? { cursor: 'pointer', onClick: fire } : {}\n // The \"datasets\" (left) handler fires for a center node and its left flow.\n const categoryFire = (name: string) =>\n onCategoryClick ? () => onCategoryClick(name) : undefined\n\n return (\n <div className={classNames(styles.root, { [styles.rootVisible]: visible })}>\n {title && (\n <div className={styles.title} style={{ fontFamily, color: textColor }}>\n {title}\n </div>\n )}\n <svg\n viewBox={`0 0 ${VIEW_W} ${viewH}`}\n role=\"img\"\n aria-label={\n breakdownLabel\n ? `${rootLabel} broken down ${breakdownLabel}`\n : `${rootLabel} breakdown`\n }\n className={styles.svg}\n style={{ fontFamily, maxWidth: VIEW_W }}\n onMouseLeave={() => setHovered(null)}\n >\n <defs>\n {graph.links.map((link, i) => {\n const source = link.source as LaidOutNode\n const target = link.target as LaidOutNode\n return (\n <linearGradient\n key={i}\n id={`${gradientPrefix}-grad-${i}`}\n gradientUnits=\"userSpaceOnUse\"\n x1={source.x1}\n x2={target.x0}\n >\n <stop offset=\"0%\" stopColor={source.color} />\n <stop offset=\"100%\" stopColor={target.color} />\n </linearGradient>\n )\n })}\n </defs>\n\n {/* Ribbons */}\n <g fill=\"none\">\n {graph.links.map((link, i) => {\n const sourceNode = (\n link.side === 'left' ? link.target : link.source\n ) as LaidOutNode\n const baseWidth = Math.max(1, link.width ?? 1)\n const handler =\n link.side === 'left' ? onCategoryClick : onRightCategoryClick\n const fire = handler ? () => handler(sourceNode.name) : undefined\n return (\n <path\n key={i}\n d={linkPath(link) ?? undefined}\n stroke={`url(#${gradientPrefix}-grad-${i})`}\n strokeWidth={\n clicked === link.sourceIndex ? baseWidth * 1.25 : baseWidth\n }\n strokeOpacity={linkOpacity(link.sourceIndex)}\n className={styles.ribbon}\n onMouseEnter={() => setHovered(link.sourceIndex)}\n {...flowProps(link.sourceIndex, fire)}\n />\n )\n })}\n </g>\n\n {/* Nodes */}\n <g>\n {graph.nodes.map((node, i) => {\n const sourceIndex = (node.index ?? 1) - 1\n const clickProps =\n node.kind === 'leftEnd'\n ? endProps(onRootClick)\n : node.kind === 'rightEnd'\n ? endProps(onRightEndClick)\n : flowProps(sourceIndex, categoryFire(node.name))\n return (\n <rect\n key={i}\n x={node.x0}\n y={node.y0}\n width={(node.x1 ?? 0) - (node.x0 ?? 0)}\n height={Math.max(1, (node.y1 ?? 0) - (node.y0 ?? 0))}\n rx={4}\n fill={node.color}\n fillOpacity={nodeOpacity(node)}\n stroke={theme.palette.background.paper}\n strokeWidth={1}\n className={styles.node}\n onMouseEnter={() =>\n setHovered(node.kind === 'source' ? sourceIndex : null)\n }\n {...clickProps}\n />\n )\n })}\n </g>\n\n {/* Labels */}\n {graph.nodes.map((node, i) => {\n if (node.kind === 'leftEnd') {\n return (\n <SankeyEndFigure\n key={`lab-${i}`}\n node={node}\n total={totalLeft}\n unitLabel={unitLabel}\n align=\"left\"\n onMouseEnter={() => setHovered(null)}\n interactiveProps={endProps(onRootClick)}\n />\n )\n }\n if (node.kind === 'rightEnd') {\n return (\n <SankeyEndFigure\n key={`lab-${i}`}\n node={node}\n total={totalRight}\n unitLabel={rightUnitLabel}\n align=\"right\"\n onMouseEnter={() => setHovered(null)}\n interactiveProps={endProps(onRightEndClick)}\n />\n )\n }\n const sourceIndex = (node.index ?? 1) - 1\n const fire = categoryFire(node.name)\n if (hasRightFlow) {\n return (\n <SankeyCenterLabel\n key={`lab-${i}`}\n node={node}\n leftValue={node.leftValue ?? 0}\n rightValue={node.rightValue ?? 0}\n unitLabel={unitLabel}\n rightUnitLabel={rightUnitLabel}\n opacity={labelOpacity(sourceIndex)}\n onMouseEnter={() => setHovered(sourceIndex)}\n interactiveProps={flowProps(sourceIndex, fire)}\n />\n )\n }\n return (\n <SankeyCategoryLabel\n key={`lab-${i}`}\n node={node}\n total={totalLeft}\n opacity={labelOpacity(sourceIndex)}\n onMouseEnter={() => setHovered(sourceIndex)}\n interactiveProps={flowProps(sourceIndex, fire)}\n />\n )\n })}\n </svg>\n </div>\n )\n}\n\nexport default SynapseSankeyPlot\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import './SynapseSankeyPlot.css';var e = {
2
+ root: "_root_244go_1",
3
+ rootVisible: "_rootVisible_244go_8",
4
+ title: "_title_244go_12",
5
+ svg: "_svg_244go_19",
6
+ ribbon: "_ribbon_244go_28",
7
+ node: "_node_244go_32",
8
+ categoryLabel: "_categoryLabel_244go_36",
9
+ tabularNums: "_tabularNums_244go_40",
10
+ haloText: "_haloText_244go_44"
11
+ };
12
+ //#endregion
13
+ export { e as default };
14
+
15
+ //# sourceMappingURL=SynapseSankeyPlot.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SynapseSankeyPlot.module.js","names":[],"sources":["../../../src/components/Plot/SynapseSankeyPlot.module.scss"],"sourcesContent":["// Layout/chrome for SynapseSankeyPlot. Theme-derived values (font family,\n// colors) stay inline in the component so the chart adopts each portal's MUI\n// palette; only the static structure and transitions live here.\n\n.root {\n width: 100%;\n margin-top: 48px;\n opacity: 0;\n transition: opacity 0.6s ease;\n}\n\n.rootVisible {\n opacity: 1;\n}\n\n.title {\n font-weight: 600;\n font-size: 20px;\n text-align: center;\n margin-bottom: 12px;\n}\n\n.svg {\n display: block;\n overflow: visible;\n width: 100%;\n height: auto;\n margin: 0 auto;\n outline: none;\n}\n\n.ribbon {\n transition:\n stroke-opacity 0.25s ease,\n stroke-width 0.25s ease;\n}\n\n.node {\n transition: fill-opacity 0.25s ease;\n}\n\n.categoryLabel {\n transition: opacity 0.2s ease;\n}\n\n.tabularNums {\n font-variant-numeric: tabular-nums;\n}\n\n// White halo behind label text so it stays legible where it crosses a ribbon.\n// The stroke color is set inline from the theme background; paint-order draws\n// the stroke first (behind the fill).\n.haloText {\n paint-order: stroke;\n stroke-width: 3px;\n stroke-linejoin: round;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .root {\n transition: none;\n }\n}\n"],"mappings":""}
@@ -0,0 +1,63 @@
1
+ // Layout/chrome for SynapseSankeyPlot. Theme-derived values (font family,
2
+ // colors) stay inline in the component so the chart adopts each portal's MUI
3
+ // palette; only the static structure and transitions live here.
4
+
5
+ .root {
6
+ width: 100%;
7
+ margin-top: 48px;
8
+ opacity: 0;
9
+ transition: opacity 0.6s ease;
10
+ }
11
+
12
+ .rootVisible {
13
+ opacity: 1;
14
+ }
15
+
16
+ .title {
17
+ font-weight: 600;
18
+ font-size: 20px;
19
+ text-align: center;
20
+ margin-bottom: 12px;
21
+ }
22
+
23
+ .svg {
24
+ display: block;
25
+ overflow: visible;
26
+ width: 100%;
27
+ height: auto;
28
+ margin: 0 auto;
29
+ outline: none;
30
+ }
31
+
32
+ .ribbon {
33
+ transition:
34
+ stroke-opacity 0.25s ease,
35
+ stroke-width 0.25s ease;
36
+ }
37
+
38
+ .node {
39
+ transition: fill-opacity 0.25s ease;
40
+ }
41
+
42
+ .categoryLabel {
43
+ transition: opacity 0.2s ease;
44
+ }
45
+
46
+ .tabularNums {
47
+ font-variant-numeric: tabular-nums;
48
+ }
49
+
50
+ // White halo behind label text so it stays legible where it crosses a ribbon.
51
+ // The stroke color is set inline from the theme background; paint-order draws
52
+ // the stroke first (behind the fill).
53
+ .haloText {
54
+ paint-order: stroke;
55
+ stroke-width: 3px;
56
+ stroke-linejoin: round;
57
+ }
58
+
59
+ @media (prefers-reduced-motion: reduce) {
60
+ .root {
61
+ transition: none;
62
+ }
63
+ }
@@ -1,4 +1,4 @@
1
- import { AsynchronousJobStatus, ColumnModel, QueryBundleRequest, QueryResultBundle, RowSet } from '@sage-bionetworks/synapse-types';
1
+ import { AsynchronousJobStatus, ColumnModel, FacetColumnRangeRequest, FacetColumnValuesRequest, QueryBundleRequest, QueryResultBundle, RowSet } from '@sage-bionetworks/synapse-types';
2
2
  import type { SearchIndexQuery, SearchQueryResults, SynapseClientError } from '@sage-bionetworks/synapse-client';
3
3
  import { InfiniteData, QueryKey, UseInfiniteQueryOptions, UseSuspenseQueryOptions } from '@tanstack/react-query';
4
4
  import { KeyFactory } from '@/synapse-queries/KeyFactory';
@@ -13,17 +13,19 @@ export type SearchTableQueryUseQueryOptions = {
13
13
  rowDataInfiniteQueryOptions: UseInfiniteQueryOptions<AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>, SynapseClientError, InfiniteData<AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>>, QueryKey, string | number | undefined>;
14
14
  queryMetadataQueryOptions: UseSuspenseQueryOptions<AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>, SynapseClientError, Omit<QueryResultBundle, 'queryResult'>>;
15
15
  };
16
+ export declare function getNextPageParamForSearchQueryResults(lastPage: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>, allPages: AsynchronousJobStatus<SearchIndexQuery, QueryResultBundle>[]): number | string | undefined;
16
17
  /**
17
18
  * Converts a QueryBundleRequest (used internally for state management) into a SearchIndexQuery
18
19
  * that can be sent to the SearchQueryServicesApi.
19
20
  *
20
21
  * Mapping:
21
- * - columnModels (facetType defined) → facetRequests (columns to aggregate as facets, with optional sort config)
22
- * - query.selectedFacets (enumeration) → termsFilters (IN-clause filters)
23
- * - query.selectedFacets (range) → rangeFilters (range filters)
24
- * - query.sort → sort (SortItem { column, direction } → SearchSortField { columnName, direction })
25
- * - query.limit → limit
26
- * - query.offset → offset
22
+ * - columnModels (facetType 'enumeration') → aggregations (OpenSearch terms aggregations)
23
+ * - query.selectedFacets (enumeration) → query.bool.filter terms clauses
24
+ * - query.selectedFacets (range) → query.bool.filter range clauses
25
+ * - query.additionalFilters (TextMatchesQueryFilter) → multi_match query clause
26
+ * - query.sort → sort (SortItem { column, direction } → [{ column: 'asc'|'desc' }])
27
+ * - query.limit → size
28
+ * - query.offset → from
27
29
  * - partMask → dropped (SearchIndexQuery has no bitmask concept)
28
30
  */
29
31
  export declare function toSearchIndexQuery(queryBundleRequest: QueryBundleRequest, searchIndexId: string, columnModels?: ColumnModel[]): SearchIndexQuery;
@@ -34,18 +36,17 @@ export declare function toSearchIndexQuery(queryBundleRequest: QueryBundleReques
34
36
  * Mapping:
35
37
  * - totalHits → queryCount
36
38
  * - hits → queryResult.queryResults (rows derived from hit.rowId/rowVersion/fields)
37
- * - facets → facets (same FacetColumnResult type)
39
+ * - aggregationResults → facets (parsed from opaque OpenSearch aggregation JSON)
38
40
  */
39
- export declare function searchQueryResultsToQueryResultBundle(results: SearchQueryResults | undefined, query: SearchIndexQuery, columnModels?: ColumnModel[]): QueryResultBundle;
41
+ export declare function searchQueryResultsToQueryResultBundle(results: SearchQueryResults | undefined, query: SearchIndexQuery, columnModels?: ColumnModel[], selectedFacets?: (FacetColumnValuesRequest | FacetColumnRangeRequest)[]): QueryResultBundle;
40
42
  export declare function getSearchQueryUseQueryOptions(queryBundleRequest: QueryBundleRequest, keyFactory: KeyFactory, accessToken: string | undefined, searchIndexId: string, columnModels?: ColumnModel[]): SearchTableQueryUseQueryOptions;
41
43
  /**
42
44
  * Returns a stable callback that fetches autocomplete suggestions for a search input
43
45
  * using the synchronous `POST /search/autocomplete` endpoint.
44
46
  *
45
47
  * The query is built from the current `searchIndexId` and `autocompleteFieldName`:
46
- * - `searchQuery.queryText` is set to the user-entered search text
47
- * - `searchQuery.queryFields` is set to `[autocompleteFieldName]` so the server
48
- * only returns values for that single field
48
+ * - `searchQuery.query` is a `match_bool_prefix` clause scoped to `autocompleteFieldName`
49
+ * - `searchQuery._source` is set to `[autocompleteFieldName]` so only that field is returned
49
50
  *
50
51
  * When `autocompleteFieldName` is undefined, the returned callback immediately returns `[]`.
51
52
  */
@@ -1 +1 @@
1
- {"version":3,"file":"SearchQueryUseQueryOptions.d.ts","sourceRoot":"","sources":["../../../src/components/SearchQueryWrapper/SearchQueryUseQueryOptions.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,qBAAqB,EACrB,WAAW,EAMX,kBAAkB,EAClB,iBAAiB,EACjB,MAAM,EAIP,MAAM,iCAAiC,CAAA;AACxC,OAAO,KAAK,EAGV,gBAAgB,EAEhB,kBAAkB,EAGlB,kBAAkB,EACnB,MAAM,kCAAkC,CAAA;AAKzC,OAAO,EACL,YAAY,EACZ,QAAQ,EACR,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,uBAAuB,CAAA;AAI9B,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAEzD;;;;;GAKG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,mBAAmB,EAAE,uBAAuB,CAC1C,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,EAC1D,kBAAkB,EAClB,MAAM,GAAG,SAAS,CACnB,CAAA;IACD,2BAA2B,EAAE,uBAAuB,CAClD,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,EAC1D,kBAAkB,EAClB,YAAY,CAAC,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC,EACxE,QAAQ,EACR,MAAM,GAAG,MAAM,GAAG,SAAS,CAC5B,CAAA;IACD,yBAAyB,EAAE,uBAAuB,CAChD,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,EAC1D,kBAAkB,EAClB,IAAI,CAAC,iBAAiB,EAAE,aAAa,CAAC,CACvC,CAAA;CACF,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,gBAAgB,CAuGlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,kBAAkB,GAAG,SAAS,EACvC,KAAK,EAAE,gBAAgB,EACvB,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,iBAAiB,CAqHnB;AAED,wBAAgB,6BAA6B,CAC3C,kBAAkB,EAAE,kBAAkB,EACtC,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,+BAA+B,CA+IjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,MAAM,EACrB,qBAAqB,EAAE,MAAM,GAAG,SAAS,GACxC,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAmC3C;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,MAAM,GACjB,+BAA+B,CAmBjC"}
1
+ {"version":3,"file":"SearchQueryUseQueryOptions.d.ts","sourceRoot":"","sources":["../../../src/components/SearchQueryWrapper/SearchQueryUseQueryOptions.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,qBAAqB,EACrB,WAAW,EAEX,uBAAuB,EAIvB,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,MAAM,EAIP,MAAM,iCAAiC,CAAA;AACxC,OAAO,KAAK,EAGV,gBAAgB,EAChB,kBAAkB,EAElB,kBAAkB,EAEnB,MAAM,kCAAkC,CAAA;AACzC,OAAO,EACL,YAAY,EACZ,QAAQ,EACR,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,uBAAuB,CAAA;AAI9B,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AA6BzD;;;;;GAKG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,mBAAmB,EAAE,uBAAuB,CAC1C,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,EAC1D,kBAAkB,EAClB,MAAM,GAAG,SAAS,CACnB,CAAA;IACD,2BAA2B,EAAE,uBAAuB,CAClD,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,EAC1D,kBAAkB,EAClB,YAAY,CAAC,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC,EACxE,QAAQ,EACR,MAAM,GAAG,MAAM,GAAG,SAAS,CAC5B,CAAA;IACD,yBAAyB,EAAE,uBAAuB,CAChD,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,EAC1D,kBAAkB,EAClB,IAAI,CAAC,iBAAiB,EAAE,aAAa,CAAC,CACvC,CAAA;CACF,CAAA;AAED,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,EACpE,QAAQ,EAAE,qBAAqB,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,EAAE,GACrE,MAAM,GAAG,MAAM,GAAG,SAAS,CAyB7B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,gBAAgB,CAmHlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,kBAAkB,GAAG,SAAS,EACvC,KAAK,EAAE,gBAAgB,EACvB,YAAY,CAAC,EAAE,WAAW,EAAE,EAC5B,cAAc,CAAC,EAAE,CAAC,wBAAwB,GAAG,uBAAuB,CAAC,EAAE,GACtE,iBAAiB,CA6InB;AAED,wBAAgB,6BAA6B,CAC3C,kBAAkB,EAAE,kBAAkB,EACtC,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,+BAA+B,CAwIjC;AAED;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,MAAM,EACrB,qBAAqB,EAAE,MAAM,GAAG,SAAS,GACxC,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAoC3C;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,MAAM,GACjB,+BAA+B,CAmBjC"}
@@ -6,131 +6,144 @@ import "../../synapse-queries/index.js";
6
6
  import { useCallback as i, useMemo as a } from "react";
7
7
  import { omit as o } from "lodash-es";
8
8
  import { FACET_COLUMN_RANGE_REQUEST_CONCRETE_TYPE_VALUE as s, FACET_COLUMN_VALUES_REQUEST_CONCRETE_TYPE_VALUE as c, TEXT_MATCHES_QUERY_FILTER_CONCRETE_TYPE_VALUE as l } from "@sage-bionetworks/synapse-types";
9
- import { FacetRequestSortDirectionEnum as u, FacetRequestSortFieldEnum as d } from "@sage-bionetworks/synapse-client";
10
- import f from "dayjs";
9
+ import u from "dayjs";
11
10
  //#region src/components/SearchQueryWrapper/SearchQueryUseQueryOptions.ts
12
- function p(e, t, n) {
11
+ function d(e, t) {
12
+ let n = e.responseBody?.queryResult?.queryResults.rows?.length ?? 0, r = e.requestBody?.searchQuery?.size, i = e.responseBody?.queryCount, a = t.reduce((e, t) => e + (t.responseBody?.queryResult?.queryResults.rows?.length ?? 0), 0);
13
+ if (n !== 0 && !(r != null && n < r) && !(i != null && a >= i)) return a;
14
+ }
15
+ function f(e, t, n) {
13
16
  let r = n?.filter((e) => e.facetType === "enumeration").map((e) => {
14
17
  let t = {
15
- columnName: e.name,
16
- maxValueCount: 100
18
+ field: e.name,
19
+ size: 100
17
20
  };
18
- return e.facetSortConfig && (e.facetSortConfig.property != null && (t.sortField = e.facetSortConfig.property === "VALUE" ? d.KEY : d.COUNT), e.facetSortConfig.direction != null && (t.sortDirection = e.facetSortConfig.direction === "ASC" ? u.ASC : u.DESC)), t;
19
- }), i = e.query.selectedFacets?.filter((e) => e.concreteType === c).map((e) => ({
20
- key: e.columnName,
21
- values: e.facetValues
22
- })), a = e.query.selectedFacets?.filter((e) => e.concreteType === s).map((e) => {
23
- let t = n?.find((t) => t.name === e.columnName)?.columnType, r = (e) => !e || t !== "DATE" ? e : /^\d{4}-\d{2}-\d{2}$/.test(e) ? String(f(e).valueOf()) : e;
24
- return {
25
- key: e.columnName,
26
- min: r(e.min),
27
- max: r(e.max)
28
- };
29
- }), o = e.query.additionalFilters?.filter((e) => e.concreteType === l).map((e) => e.searchExpression).filter((e) => e != null && e.length > 0), p = o && o.length > 0 ? o.join(" ") : void 0, m = e.query.sort?.filter((e) => e.direction === "ASC" || e.direction === "DESC").map((e) => ({
30
- columnName: e.column,
31
- direction: e.direction
32
- }));
21
+ if (e.facetSortConfig?.property != null) {
22
+ let n = e.facetSortConfig.property === "VALUE" ? "_key" : "_count", r = e.facetSortConfig.direction === "DESC" ? "desc" : "asc";
23
+ t.order = { [n]: r };
24
+ }
25
+ return [e.name, { terms: t }];
26
+ }), i = r && r.length > 0 ? Object.fromEntries(r) : void 0, a = [];
27
+ e.query.selectedFacets?.filter((e) => e.concreteType === c).forEach((e) => {
28
+ a.push({ terms: { [e.columnName]: e.facetValues ?? [] } });
29
+ }), e.query.selectedFacets?.filter((e) => e.concreteType === s).forEach((e) => {
30
+ let t = n?.find((t) => t.name === e.columnName)?.columnType, r = (e) => !e || t !== "DATE" ? e : /^\d{4}-\d{2}-\d{2}$/.test(e) ? String(u(e).valueOf()) : e, i = {}, o = r(e.min), s = r(e.max);
31
+ o !== void 0 && (i.gte = o), s !== void 0 && (i.lte = s), a.push({ range: { [e.columnName]: i } });
32
+ });
33
+ let o = e.query.additionalFilters?.filter((e) => e.concreteType === l).map((e) => e.searchExpression).filter((e) => e != null && e.length > 0), d = o && o.length > 0 ? o.join(" ") : void 0, f;
34
+ f = d && a.length > 0 ? { bool: {
35
+ must: [{ multi_match: {
36
+ query: d,
37
+ fuzziness: "AUTO"
38
+ } }],
39
+ filter: a
40
+ } } : d ? { multi_match: {
41
+ query: d,
42
+ fuzziness: "AUTO"
43
+ } } : a.length > 0 ? { bool: { filter: a } } : { match_all: {} };
44
+ let p = e.query.sort?.filter((e) => e.direction === "ASC" || e.direction === "DESC").map((e) => ({ [e.column]: e.direction.toLowerCase() }));
33
45
  return {
34
46
  concreteType: "org.sagebionetworks.repo.model.search.table.SearchIndexQuery",
35
47
  searchIndexId: t,
36
48
  searchQuery: {
37
- facetRequests: r?.length ? r : void 0,
38
- termsFilters: i?.length ? i : void 0,
39
- rangeFilters: a?.length ? a : void 0,
40
- queryText: p,
41
- queryType: "MULTI_MATCH",
42
- fuzziness: "AUTO",
43
- sort: m?.length ? m : void 0,
44
- limit: e.query.limit,
45
- offset: e.query.offset
49
+ query: f,
50
+ aggregations: i,
51
+ sort: p?.length ? p : void 0,
52
+ size: e.query.limit,
53
+ from: e.query.offset
46
54
  }
47
55
  };
48
56
  }
49
- function m(e, t, n) {
57
+ function p(e, t, n, r) {
50
58
  if (!e) return { concreteType: "org.sagebionetworks.repo.model.table.QueryResultBundle" };
51
- let r = e.selectColumns?.map((e) => e.name).filter((e) => !!e) ?? [], i = r.map((e) => ({
59
+ let i = e.selectColumns?.map((e) => e.name).filter((e) => !!e) ?? [], a = i.map((e) => ({
52
60
  name: e,
53
61
  columnType: n?.find((t) => t.name === e)?.columnType ?? "STRING"
54
- })), a = (e.hits ?? []).map((e) => ({
62
+ })), o = (e.hits ?? []).map((e) => ({
55
63
  rowId: e.rowId,
56
64
  versionNumber: e.rowVersion,
57
- values: r.map((t) => e.fields?.find((e) => e.name === t)?.value ?? null)
58
- })), o = i.length > 0 || a.length > 0 ? {
65
+ values: i.map((t) => e.fields?.find((e) => e.name === t)?.value ?? null)
66
+ })), l = a.length > 0 || o.length > 0 ? {
59
67
  concreteType: "org.sagebionetworks.repo.model.table.QueryResult",
60
68
  queryResults: {
61
69
  concreteType: "org.sagebionetworks.repo.model.table.RowSet",
62
70
  tableId: t.searchIndexId ?? "",
63
71
  etag: "",
64
- headers: i,
65
- rows: a
72
+ headers: a,
73
+ rows: o
66
74
  }
67
- } : void 0, s = e.facets, c = (n ?? []).filter((e) => e.facetType === "range" && (e.columnType === "DATE" || e.columnType === "DOUBLE" || e.columnType === "INTEGER") && !(s ?? []).some((t) => t.columnName === e.name)).map((e) => {
68
- let n = t.searchQuery?.rangeFilters?.find((t) => t.key === e.name), r = (t) => !t || e.columnType !== "DATE" ? t : /^\d+$/.test(t) ? f(parseInt(t)).format("YYYY-MM-DD") : t;
75
+ } : void 0, u = e.aggregationResults, d = Object.entries(u ?? {}).map(([e, t]) => {
76
+ let n = r?.filter((t) => t.concreteType === c && t.columnName === e).flatMap((e) => e.facetValues ?? []) ?? [];
77
+ return {
78
+ concreteType: "org.sagebionetworks.repo.model.table.FacetColumnResultValues",
79
+ facetType: "enumeration",
80
+ columnName: e,
81
+ facetValues: (t.buckets ?? []).map((e) => ({
82
+ value: String(e.key),
83
+ count: e.doc_count,
84
+ isSelected: n.includes(String(e.key))
85
+ }))
86
+ };
87
+ }), f = (n ?? []).filter((e) => e.facetType === "range" && (e.columnType === "DATE" || e.columnType === "DOUBLE" || e.columnType === "INTEGER") && !d.some((t) => t.columnName === e.name)).map((e) => {
88
+ let t = r?.find((t) => t.concreteType === s && t.columnName === e.name);
69
89
  return {
70
90
  concreteType: "org.sagebionetworks.repo.model.table.FacetColumnResultRange",
71
91
  facetType: "range",
72
92
  columnName: e.name,
73
93
  columnMin: "",
74
94
  columnMax: "",
75
- selectedMin: r(n?.min),
76
- selectedMax: r(n?.max)
95
+ selectedMin: t?.min,
96
+ selectedMax: t?.max
77
97
  };
78
- }), l = [...s ?? [], ...c], u = n ? [...l.filter((e) => n.some((t) => t.name === e.columnName)).sort((e, t) => n.findIndex((t) => t.name === e.columnName) - n.findIndex((e) => e.name === t.columnName)), ...l.filter((e) => !n.some((t) => t.name === e.columnName))] : l;
98
+ }), p = [...d ?? [], ...f], m = n ? [...p.filter((e) => n.some((t) => t.name === e.columnName)).sort((e, t) => n.findIndex((t) => t.name === e.columnName) - n.findIndex((e) => e.name === t.columnName)), ...p.filter((e) => !n.some((t) => t.name === e.columnName))] : p;
79
99
  return {
80
100
  concreteType: "org.sagebionetworks.repo.model.table.QueryResultBundle",
81
101
  queryCount: e.totalHits,
82
- selectColumns: i,
83
- queryResult: o,
84
- facets: u
102
+ selectColumns: a,
103
+ queryResult: l,
104
+ facets: m
85
105
  };
86
106
  }
87
- function h(t, n, i, a, s) {
88
- let c = p(t, a, s), l = {
107
+ function m(t, n, i, a, s) {
108
+ let c = f(t, a, s), l = {
89
109
  ...c,
90
110
  searchQuery: {
91
111
  ...c.searchQuery,
92
- facetRequests: void 0
112
+ aggregations: void 0
93
113
  },
94
114
  responseParts: new Set(["HITS", "SELECT_COLUMNS"])
95
115
  }, u = {
96
116
  ...c,
97
- responseParts: new Set([
98
- "TOTAL_HITS",
99
- "SELECT_COLUMNS",
100
- "FACETS"
101
- ])
102
- }, d = (e) => ({
117
+ responseParts: new Set(["TOTAL_HITS", "SELECT_COLUMNS"])
118
+ }, m = (e) => ({
103
119
  ...e,
104
120
  responseParts: e.responseParts ? [...e.responseParts].sort() : void 0
105
- }), f = async (t) => {
106
- let n = await e(t, i);
121
+ }), h = async (n) => {
122
+ let r = await e(n, i);
107
123
  return {
108
- ...n,
109
- responseBody: m(n.responseBody, t, s)
124
+ ...r,
125
+ responseBody: p(r.responseBody, n, s, t.query.selectedFacets)
110
126
  };
111
127
  };
112
128
  return {
113
129
  rowDataQueryOptions: {
114
130
  ...r,
115
- queryKey: n.getSearchQueryResultWithAsyncStatusQueryKey(d(l), !1),
116
- queryFn: () => f(l),
131
+ queryKey: n.getSearchQueryResultWithAsyncStatusQueryKey(m(l), !1),
132
+ queryFn: () => h(l),
117
133
  select: (e) => e.responseBody?.queryResult?.queryResults
118
134
  },
119
135
  rowDataInfiniteQueryOptions: {
120
136
  ...r,
121
- queryKey: n.getSearchQueryResultWithAsyncStatusQueryKey(d(l), !0),
137
+ queryKey: n.getSearchQueryResultWithAsyncStatusQueryKey(m(l), !0),
122
138
  initialPageParam: 0,
123
- getNextPageParam: (e, t) => {
124
- let n = e.responseBody?.queryCount, r = t.reduce((e, t) => e + (t.responseBody?.queryResult?.queryResults.rows?.length ?? 0), 0);
125
- if (!(n != null && r >= n)) return r;
126
- },
139
+ getNextPageParam: (e, t) => d(e, t),
127
140
  queryFn: (e) => {
128
141
  let t = typeof e.pageParam == "string" ? parseInt(e.pageParam) : e.pageParam ?? 0;
129
- return f({
142
+ return h({
130
143
  ...l,
131
144
  searchQuery: {
132
145
  ...l.searchQuery,
133
- offset: t
146
+ from: t
134
147
  }
135
148
  });
136
149
  },
@@ -138,8 +151,8 @@ function h(t, n, i, a, s) {
138
151
  },
139
152
  queryMetadataQueryOptions: {
140
153
  ...r,
141
- queryKey: n.getSearchQueryResultWithAsyncStatusQueryKey(d(u), !1),
142
- queryFn: () => f(u),
154
+ queryKey: n.getSearchQueryResultWithAsyncStatusQueryKey(m(u), !1),
155
+ queryFn: () => h(u),
143
156
  select: (e) => {
144
157
  let t = o(e.responseBody ?? {}, "queryResult");
145
158
  return s ? {
@@ -150,19 +163,17 @@ function h(t, n, i, a, s) {
150
163
  }
151
164
  };
152
165
  }
153
- function g(e, n) {
166
+ function h(e, n) {
154
167
  let { synapseClient: r } = t();
155
168
  return i(async (t) => {
156
169
  if (!n) return [];
157
170
  let i = t.trim();
158
171
  if (!i) return [];
159
- let a = await r.searchManagementServicesClient.postRepoV1SearchAutocomplete({ searchIndexQuery: {
160
- concreteType: "org.sagebionetworks.repo.model.search.table.SearchIndexQuery",
172
+ let a = await r.searchManagementServicesClient.postRepoV1SearchAutocomplete({ searchAutocompleteRequest: {
161
173
  searchIndexId: e,
162
174
  searchQuery: {
163
- queryText: i,
164
- queryFields: [n],
165
- returnFields: [n]
175
+ query: { match_bool_prefix: { [n]: { query: i } } },
176
+ _source: { includes: [n] }
166
177
  }
167
178
  } }), o = [];
168
179
  for (let e of a.hits ?? []) for (let t of e.fields ?? []) t.value && o.push(t.value);
@@ -173,9 +184,9 @@ function g(e, n) {
173
184
  n
174
185
  ]);
175
186
  }
176
- function _(e, r, i) {
187
+ function g(e, r, i) {
177
188
  let { keyFactory: o, accessToken: s } = t(), { data: c } = n(i, void 0, { includeTableBundle: !0 }), l = c?.tableBundle?.columnModels;
178
- return a(() => h(e, o, s, r, l), [
189
+ return a(() => m(e, o, s, r, l), [
179
190
  o,
180
191
  s,
181
192
  e,
@@ -184,6 +195,6 @@ function _(e, r, i) {
184
195
  ]);
185
196
  }
186
197
  //#endregion
187
- export { h as getSearchQueryUseQueryOptions, m as searchQueryResultsToQueryResultBundle, p as toSearchIndexQuery, g as useGetSuggestionsForSearchIndex, _ as useSearchQueryUseQueryOptions };
198
+ export { d as getNextPageParamForSearchQueryResults, m as getSearchQueryUseQueryOptions, p as searchQueryResultsToQueryResultBundle, f as toSearchIndexQuery, h as useGetSuggestionsForSearchIndex, g as useSearchQueryUseQueryOptions };
188
199
 
189
200
  //# sourceMappingURL=SearchQueryUseQueryOptions.js.map