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.
- package/dist/SWC.index.js +1 -1
- package/dist/components/CardContainer/CardConfiguration.d.ts +2 -0
- package/dist/components/CardContainer/CardConfiguration.d.ts.map +1 -1
- package/dist/components/CardContainer/CardContainer.d.ts.map +1 -1
- package/dist/components/CardContainer/CardContainer.js +3 -3
- package/dist/components/CardContainer/CardContainer.js.map +1 -1
- package/dist/components/CardContainerLogic/CardContainerLogic.d.ts +1 -0
- package/dist/components/CardContainerLogic/CardContainerLogic.d.ts.map +1 -1
- package/dist/components/CardContainerLogic/CardContainerLogic.js.map +1 -1
- package/dist/components/DataExplorer/DataExplorer.css +1 -1
- package/dist/components/DataExplorer/DataExplorer.module.js +16 -16
- package/dist/components/DataExplorer/DataExplorer.module.js.map +1 -1
- package/dist/components/DataExplorer/DataExplorer.module.scss +26 -6
- package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.d.ts +5 -3
- package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.d.ts.map +1 -1
- package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.js +46 -47
- package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.js.map +1 -1
- package/dist/components/DataGrid/hooks/useColumnResizeHandles.d.ts.map +1 -1
- package/dist/components/DataGrid/hooks/useColumnResizeHandles.js +1 -1
- package/dist/components/DataGrid/hooks/useColumnResizeHandles.js.map +1 -1
- package/dist/components/DataGrid/utils/columnFactory.d.ts.map +1 -1
- package/dist/components/DataGrid/utils/columnFactory.js +1 -0
- package/dist/components/DataGrid/utils/columnFactory.js.map +1 -1
- package/dist/components/GenericCard/GenericCard.d.ts +2 -0
- package/dist/components/GenericCard/GenericCard.d.ts.map +1 -1
- package/dist/components/GenericCard/GenericCard.js +76 -64
- package/dist/components/GenericCard/GenericCard.js.map +1 -1
- package/dist/components/GenericCard/TableRowGenericCard.d.ts.map +1 -1
- package/dist/components/GenericCard/TableRowGenericCard.js +33 -25
- package/dist/components/GenericCard/TableRowGenericCard.js.map +1 -1
- package/dist/components/Plot/SynapseSankeyPlot.css +1 -0
- package/dist/components/Plot/SynapseSankeyPlot.d.ts +44 -2
- package/dist/components/Plot/SynapseSankeyPlot.d.ts.map +1 -1
- package/dist/components/Plot/SynapseSankeyPlot.js +343 -38
- package/dist/components/Plot/SynapseSankeyPlot.js.map +1 -1
- package/dist/components/Plot/SynapseSankeyPlot.module.js +15 -0
- package/dist/components/Plot/SynapseSankeyPlot.module.js.map +1 -0
- package/dist/components/Plot/SynapseSankeyPlot.module.scss +63 -0
- package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.d.ts +13 -12
- package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.d.ts.map +1 -1
- package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js +88 -77
- package/dist/components/SearchQueryWrapper/SearchQueryUseQueryOptions.js.map +1 -1
- package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.d.ts.map +1 -1
- package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.js +63 -74
- package/dist/components/SynapseTable/TopLevelControls/TopLevelControls.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ColumnModelForm.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js +72 -68
- package/dist/components/TableColumnSchemaEditor/ColumnModelForm.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts +27 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.js +47 -36
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaEditorUtils.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaForm.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/TableColumnSchemaFormReducer.d.ts +12 -12
- package/dist/components/TableColumnSchemaEditor/Validators/BooleanSchema.d.ts +4 -1
- package/dist/components/TableColumnSchemaEditor/Validators/BooleanSchema.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.d.ts +167 -517
- package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.js +65 -65
- package/dist/components/TableColumnSchemaEditor/Validators/ColumnModelValidator.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/DatetimeSchema.d.ts +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/DatetimeSchema.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/DoubleSchema.d.ts +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/DoubleSchema.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/DoubleSchema.js +6 -13
- package/dist/components/TableColumnSchemaEditor/Validators/DoubleSchema.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/EntityIdSchema.d.ts +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/EntityIdSchema.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/IntegerSchema.d.ts +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/IntegerSchema.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/IntegerSchema.js +2 -2
- package/dist/components/TableColumnSchemaEditor/Validators/IntegerSchema.js.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/OptionalStringSchema.d.ts +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/OptionalStringSchema.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/getZodSchemaForColumnType.d.ts +2 -2
- package/dist/components/TableColumnSchemaEditor/Validators/getZodSchemaForColumnType.d.ts.map +1 -1
- package/dist/components/TableColumnSchemaEditor/Validators/getZodSchemaForColumnType.js +15 -16
- package/dist/components/TableColumnSchemaEditor/Validators/getZodSchemaForColumnType.js.map +1 -1
- package/dist/mocks/mockSearchQueryData.js +2 -2
- package/dist/mocks/mockSearchQueryData.js.map +1 -1
- package/dist/mocks/msw/handlers/searchQueryHandlers.d.ts +1 -1
- package/dist/mocks/msw/handlers/searchQueryHandlers.d.ts.map +1 -1
- package/dist/mocks/msw/handlers/searchQueryHandlers.js +6 -3
- package/dist/mocks/msw/handlers/searchQueryHandlers.js.map +1 -1
- package/dist/mocks/query/mockUserCardTableQueryResultBundle.d.ts +13 -0
- package/dist/mocks/query/mockUserCardTableQueryResultBundle.d.ts.map +1 -1
- package/dist/mocks/query/mockUserCardTableQueryResultBundle.js +27 -0
- package/dist/mocks/query/mockUserCardTableQueryResultBundle.js.map +1 -1
- package/dist/style/components/_cards.scss +10 -0
- package/dist/style/components/_data-grid-extra.css +1 -1
- package/dist/style/components/_data-grid-extra.scss +7 -1
- package/dist/style/main.css +1 -1
- package/dist/synapse-client/SynapseClient.d.ts.map +1 -1
- package/dist/synapse-client/SynapseClient.js +497 -495
- package/dist/synapse-client/SynapseClient.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- 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
|
|
22
|
-
* - query.selectedFacets (enumeration) →
|
|
23
|
-
* - query.selectedFacets (range) →
|
|
24
|
-
* - query.
|
|
25
|
-
* - query.
|
|
26
|
-
* - query.
|
|
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
|
-
* -
|
|
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.
|
|
47
|
-
* - `searchQuery.
|
|
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,
|
|
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
|
|
10
|
-
import f from "dayjs";
|
|
9
|
+
import u from "dayjs";
|
|
11
10
|
//#region src/components/SearchQueryWrapper/SearchQueryUseQueryOptions.ts
|
|
12
|
-
function
|
|
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
|
-
|
|
16
|
-
|
|
18
|
+
field: e.name,
|
|
19
|
+
size: 100
|
|
17
20
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
|
57
|
+
function p(e, t, n, r) {
|
|
50
58
|
if (!e) return { concreteType: "org.sagebionetworks.repo.model.table.QueryResultBundle" };
|
|
51
|
-
let
|
|
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
|
-
})),
|
|
62
|
+
})), o = (e.hits ?? []).map((e) => ({
|
|
55
63
|
rowId: e.rowId,
|
|
56
64
|
versionNumber: e.rowVersion,
|
|
57
|
-
values:
|
|
58
|
-
})),
|
|
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:
|
|
65
|
-
rows:
|
|
72
|
+
headers: a,
|
|
73
|
+
rows: o
|
|
66
74
|
}
|
|
67
|
-
} : void 0,
|
|
68
|
-
let n =
|
|
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:
|
|
76
|
-
selectedMax:
|
|
95
|
+
selectedMin: t?.min,
|
|
96
|
+
selectedMax: t?.max
|
|
77
97
|
};
|
|
78
|
-
}),
|
|
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:
|
|
83
|
-
queryResult:
|
|
84
|
-
facets:
|
|
102
|
+
selectColumns: a,
|
|
103
|
+
queryResult: l,
|
|
104
|
+
facets: m
|
|
85
105
|
};
|
|
86
106
|
}
|
|
87
|
-
function
|
|
88
|
-
let c =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}),
|
|
106
|
-
let
|
|
121
|
+
}), h = async (n) => {
|
|
122
|
+
let r = await e(n, i);
|
|
107
123
|
return {
|
|
108
|
-
...
|
|
109
|
-
responseBody:
|
|
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(
|
|
116
|
-
queryFn: () =>
|
|
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(
|
|
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
|
|
142
|
+
return h({
|
|
130
143
|
...l,
|
|
131
144
|
searchQuery: {
|
|
132
145
|
...l.searchQuery,
|
|
133
|
-
|
|
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(
|
|
142
|
-
queryFn: () =>
|
|
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
|
|
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({
|
|
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
|
-
|
|
164
|
-
|
|
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
|
|
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(() =>
|
|
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 {
|
|
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
|