synapse-react-client 4.0.21 → 4.0.22
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.d.ts +1 -0
- package/dist/SWC.index.d.ts.map +1 -1
- package/dist/SWC.index.js +2 -1
- package/dist/SWC.index.js.map +1 -1
- package/dist/components/CardContainer/CardContainer.d.ts.map +1 -1
- package/dist/components/CardContainer/CardContainer.js +43 -49
- package/dist/components/CardContainer/CardContainer.js.map +1 -1
- package/dist/components/CardContainerLogic/CardContainerLogic.d.ts +13 -0
- package/dist/components/CardContainerLogic/CardContainerLogic.d.ts.map +1 -1
- package/dist/components/CardContainerLogic/CardContainerLogic.js +64 -40
- package/dist/components/CardContainerLogic/CardContainerLogic.js.map +1 -1
- package/dist/components/ChallengeSubmission/ChallengeSubmissionStepper.js +1 -1
- package/dist/components/ChallengeSubmission/ChallengeSubmissionStepper.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 +0 -1
- package/dist/components/DataGrid/DataGrid.d.ts +1 -0
- package/dist/components/DataGrid/DataGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/DataGrid.js +72 -72
- package/dist/components/DataGrid/DataGrid.js.map +1 -1
- package/dist/components/DataGrid/SynapseGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/SynapseGrid.js +209 -206
- package/dist/components/DataGrid/SynapseGrid.js.map +1 -1
- package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.d.ts +2 -1
- package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.d.ts.map +1 -1
- package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.js +51 -42
- package/dist/components/DataGrid/components/ColumnHeaderWithTooltip.js.map +1 -1
- package/dist/components/DataGrid/useDataGridWebsocket.d.ts.map +1 -1
- package/dist/components/DataGrid/useDataGridWebsocket.js +68 -67
- package/dist/components/DataGrid/useDataGridWebsocket.js.map +1 -1
- package/dist/components/DataGrid/utils/columnFactory.d.ts +1 -0
- package/dist/components/DataGrid/utils/columnFactory.d.ts.map +1 -1
- package/dist/components/DataGrid/utils/columnFactory.js +4 -3
- package/dist/components/DataGrid/utils/columnFactory.js.map +1 -1
- package/dist/components/DataGrid/utils/modelColsToGrid.d.ts +1 -1
- package/dist/components/DataGrid/utils/modelColsToGrid.d.ts.map +1 -1
- package/dist/components/DataGrid/utils/modelColsToGrid.js +15 -14
- package/dist/components/DataGrid/utils/modelColsToGrid.js.map +1 -1
- package/dist/components/DataGrid/utils/normalizeWebsocketError.d.ts +7 -0
- package/dist/components/DataGrid/utils/normalizeWebsocketError.d.ts.map +1 -0
- package/dist/components/DataGrid/utils/normalizeWebsocketError.js +8 -0
- package/dist/components/DataGrid/utils/normalizeWebsocketError.js.map +1 -0
- package/dist/components/Goals/Goals.d.ts +8 -0
- package/dist/components/Goals/Goals.d.ts.map +1 -1
- package/dist/components/Goals/Goals.js +54 -40
- package/dist/components/Goals/Goals.js.map +1 -1
- package/dist/components/ProjectVisibilityChip/ProjectVisibilityChip.d.ts +9 -0
- package/dist/components/ProjectVisibilityChip/ProjectVisibilityChip.d.ts.map +1 -0
- package/dist/components/ProjectVisibilityChip/ProjectVisibilityChip.js +69 -0
- package/dist/components/ProjectVisibilityChip/ProjectVisibilityChip.js.map +1 -0
- package/dist/components/ProjectVisibilityChip/getProjectVisibilityFromACL.d.ts +13 -0
- package/dist/components/ProjectVisibilityChip/getProjectVisibilityFromACL.d.ts.map +1 -0
- package/dist/components/ProjectVisibilityChip/getProjectVisibilityFromACL.js +11 -0
- package/dist/components/ProjectVisibilityChip/getProjectVisibilityFromACL.js.map +1 -0
- package/dist/components/ProjectVisibilityChip/index.d.ts +5 -0
- package/dist/components/ProjectVisibilityChip/index.d.ts.map +1 -0
- package/dist/components/ProjectVisibilityChip/index.js +7 -0
- package/dist/components/ProjectVisibilityChip/index.js.map +1 -0
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.d.ts.map +1 -1
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js +1 -1
- package/dist/components/QueryVisualizationWrapper/QueryVisualizationWrapper.js.map +1 -1
- package/dist/components/QueryWrapperPlotNav/RowSetView.d.ts.map +1 -1
- package/dist/components/QueryWrapperPlotNav/RowSetView.js +9 -12
- package/dist/components/QueryWrapperPlotNav/RowSetView.js.map +1 -1
- package/dist/components/RssFeedCards/RssFeedCards.d.ts +7 -15
- package/dist/components/RssFeedCards/RssFeedCards.d.ts.map +1 -1
- package/dist/components/RssFeedCards/RssFeedCards.js +114 -123
- package/dist/components/RssFeedCards/RssFeedCards.js.map +1 -1
- package/dist/components/UserCardList/UserCardList.d.ts +2 -20
- package/dist/components/UserCardList/UserCardList.d.ts.map +1 -1
- package/dist/components/UserCardList/UserCardList.js +49 -72
- package/dist/components/UserCardList/UserCardList.js.map +1 -1
- package/dist/components/UserCardList/UserCardListRotate.d.ts +13 -0
- package/dist/components/UserCardList/UserCardListRotate.d.ts.map +1 -1
- package/dist/components/UserCardList/UserCardListRotate.js +82 -57
- package/dist/components/UserCardList/UserCardListRotate.js.map +1 -1
- package/dist/style/abstracts/_cssVariables.scss +1 -0
- package/dist/style/main.css +1 -1
- package/dist/synapse-queries/KeyFactory.d.ts +1 -0
- package/dist/synapse-queries/KeyFactory.d.ts.map +1 -1
- package/dist/synapse-queries/KeyFactory.js +3 -0
- package/dist/synapse-queries/KeyFactory.js.map +1 -1
- package/dist/synapse-queries/index.js +46 -44
- package/dist/synapse-queries/user/index.js +3 -3
- package/dist/synapse-queries/user/useUserBundle.d.ts +12 -0
- package/dist/synapse-queries/user/useUserBundle.d.ts.map +1 -1
- package/dist/synapse-queries/user/useUserBundle.js +50 -36
- package/dist/synapse-queries/user/useUserBundle.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/AppUtils/session/SessionInitializedGuard.d.ts +10 -5
- package/dist/utils/AppUtils/session/SessionInitializedGuard.d.ts.map +1 -1
- package/dist/utils/AppUtils/session/SessionInitializedGuard.js +13 -9
- package/dist/utils/AppUtils/session/SessionInitializedGuard.js.map +1 -1
- package/dist/utils/functions/SqlFunctions.d.ts +1 -1
- package/dist/utils/functions/SqlFunctions.d.ts.map +1 -1
- package/dist/utils/functions/SqlFunctions.js +1 -1
- package/dist/utils/functions/SqlFunctions.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDataGridWebsocket.js","names":["GridModel","useCRDTModelView","useCallback","useEffect","useMemo","useReducer","useRef","DataGridWebSocket","useEstablishWebsocketConnection","useDocumentVisibility","WebSocketState","model","hasCompletedInitialSync","isSyncing","isConnected","isConnecting","connectionParams","replicaId","sessionId","websocketInstance","connectionAttemptId","connectionError","websocketError","WebSocketAction","type","payload","attemptId","websocketReducer","state","action","isSameConnection","initialWebSocketState","UseDataGridWebSocketOptions","onGridReady","onReplicaConnected","onReplicaDisconnected","useDataGridWebSocket","options","dispatch","connectionAttemptCounter","activeConnectionAttemptIdRef","modelSnapshot","isDocumentVisible","mutateAsync","establishWebsocketConnection","isPending","isEstablishingWebsocketConnection","error","errorEstablishingWebsocketConnection","presignedUrl","reset","resetEstablishWebsocketConnection","clearPresignedUrl","handleModelCreate","newModel","websocketOptionsWithoutModel","onStatusChange","open","onModelCreate","onSyncStart","onSyncEnd","onError","connect","isDifferentConnection","current","websocketOptions","then","ws","disconnect","catch","err","console","previousConnectionParams","previous","isModelRenderable","api","getSnapshot","columnNames","columnOrder","rows","columnsReady","length","orderReady","rowsReady","hasSufficientData"],"sources":["../../../src/components/DataGrid/useDataGridWebsocket.ts"],"sourcesContent":["import { GridModel } from '@/components/DataGrid/DataGridTypes'\nimport { useCRDTModelView } from '@/components/DataGrid/useCRDTModelView'\nimport { useCallback, useEffect, useMemo, useReducer, useRef } from 'react'\nimport { DataGridWebSocket } from './DataGridWebSocket'\nimport { useEstablishWebsocketConnection } from '@/synapse-queries/grid/useEstablishWebsocketConnection'\nimport { useDocumentVisibility } from '@react-hookz/web'\n\n// State type\ninterface WebSocketState {\n model: GridModel | null\n /**\n * True if the WebSocket has finished the initial sync and can process CRDT updates.\n * Corresponds to the `GRID_READY` action.\n */\n hasCompletedInitialSync: boolean\n /**\n * True while a clock-sync exchange is in progress. Set on every outgoing\n * `synchronize-clock` and cleared on `ResponseComplete`, which the server\n * sends once per exchange to signal \"we're synchronized\" — not per request.\n */\n isSyncing: boolean\n isConnected: boolean\n isConnecting: boolean\n connectionParams: {\n replicaId: number\n sessionId: string\n } | null\n websocketInstance: DataGridWebSocket | null\n connectionAttemptId: number | null\n connectionError: unknown\n websocketError: unknown\n}\n\n// Action types\ntype WebSocketAction =\n | {\n type: 'CONNECT_REQUESTED'\n payload: { replicaId: number; sessionId: string; attemptId: number }\n }\n | { type: 'CONNECTION_ESTABLISHED'; payload: DataGridWebSocket }\n | { type: 'CONNECTION_OPENED' }\n | { type: 'CONNECTION_CLOSED' }\n | { type: 'GRID_READY' }\n | { type: 'SYNC_STARTED' }\n | { type: 'SYNC_ENDED' }\n | { type: 'MODEL_CREATED'; payload: GridModel }\n | { type: 'CONNECTION_ERROR'; payload: unknown }\n | { type: 'WEBSOCKET_ERROR'; payload: unknown }\n\n// Reducer function\nfunction websocketReducer(\n state: WebSocketState,\n action: WebSocketAction,\n): WebSocketState {\n switch (action.type) {\n case 'CONNECT_REQUESTED': {\n const isSameConnection =\n state.connectionParams &&\n state.connectionParams.replicaId === action.payload.replicaId &&\n state.connectionParams.sessionId === action.payload.sessionId\n\n return {\n ...state,\n connectionParams: {\n replicaId: action.payload.replicaId,\n sessionId: action.payload.sessionId,\n },\n hasCompletedInitialSync: isSameConnection\n ? state.hasCompletedInitialSync\n : false,\n isSyncing: false,\n model: isSameConnection ? state.model : null,\n isConnected: false,\n isConnecting: false,\n connectionAttemptId: action.payload.attemptId,\n connectionError: null,\n }\n }\n\n case 'CONNECTION_ESTABLISHED':\n return {\n ...state,\n websocketInstance: action.payload,\n isConnecting: true,\n }\n\n case 'CONNECTION_OPENED':\n return {\n ...state,\n isConnected: true,\n isConnecting: false,\n }\n\n case 'CONNECTION_CLOSED':\n return {\n ...state,\n isConnected: false,\n isConnecting: false,\n isSyncing: false,\n }\n\n case 'GRID_READY':\n return {\n ...state,\n hasCompletedInitialSync: true,\n }\n\n case 'SYNC_STARTED':\n return {\n ...state,\n isSyncing: true,\n }\n\n case 'SYNC_ENDED':\n return {\n ...state,\n isSyncing: false,\n }\n\n case 'MODEL_CREATED':\n return {\n ...state,\n model: action.payload,\n }\n\n case 'CONNECTION_ERROR':\n return {\n ...state,\n connectionError: action.payload,\n isConnecting: false,\n }\n\n case 'WEBSOCKET_ERROR':\n return {\n ...state,\n websocketError: action.payload,\n }\n\n default:\n return state\n }\n}\n\nexport const initialWebSocketState: WebSocketState = {\n model: null,\n hasCompletedInitialSync: false,\n isSyncing: false,\n isConnected: false,\n isConnecting: false,\n connectionParams: null,\n websocketInstance: null,\n connectionAttemptId: null,\n connectionError: null,\n websocketError: null,\n}\n\n/**\n * Custom hook to manage a DataGrid WebSocket connection.\n * Handles:\n * - Fetching presigned URLs via a mutation hook\n * - Instantiating the DataGridWebSocket\n * - Connection status tracking\n * - Reconnection on disconnect\n * - Grid model updates and snapshot tracking\n */\nexport interface UseDataGridWebSocketOptions {\n onGridReady?: () => void\n onReplicaConnected?: () => void\n onReplicaDisconnected?: () => void\n}\n\nexport function useDataGridWebSocket(options?: UseDataGridWebSocketOptions) {\n const [state, dispatch] = useReducer(websocketReducer, initialWebSocketState)\n\n const connectionAttemptCounter = useRef(0)\n const activeConnectionAttemptIdRef = useRef<number | null>(null)\n\n const modelSnapshot = useCRDTModelView(state.model)\n\n const isDocumentVisible = useDocumentVisibility()\n\n const {\n mutateAsync: establishWebsocketConnection,\n isPending: isEstablishingWebsocketConnection,\n error: errorEstablishingWebsocketConnection,\n presignedUrl,\n reset: resetEstablishWebsocketConnection,\n clearPresignedUrl,\n } = useEstablishWebsocketConnection()\n\n // Update model creation handler - only set model, don't reset to null on disconnect\n const handleModelCreate = useCallback(\n (newModel: GridModel) => {\n dispatch({ type: 'MODEL_CREATED', payload: newModel })\n },\n [dispatch],\n )\n\n // Memoize websocket options to prevent unnecessary re-renders (excluding model to avoid circular deps)\n const websocketOptionsWithoutModel = useMemo(\n () => ({\n onGridReady: () => {\n dispatch({ type: 'GRID_READY' })\n options?.onGridReady?.()\n },\n onStatusChange: (open: boolean) =>\n dispatch({ type: open ? 'CONNECTION_OPENED' : 'CONNECTION_CLOSED' }),\n onModelCreate: handleModelCreate,\n onReplicaConnected: options?.onReplicaConnected,\n onReplicaDisconnected: options?.onReplicaDisconnected,\n onSyncStart: () => dispatch({ type: 'SYNC_STARTED' }),\n onSyncEnd: () => dispatch({ type: 'SYNC_ENDED' }),\n onError: (error: unknown) =>\n dispatch({ type: 'WEBSOCKET_ERROR', payload: error }),\n }),\n [\n handleModelCreate,\n options?.onGridReady,\n options?.onReplicaConnected,\n options?.onReplicaDisconnected,\n ],\n )\n\n // Initiate (or re-initiate) a connection\n const connect = useCallback(\n (replicaId: number, sessionId: string) => {\n resetEstablishWebsocketConnection()\n\n const isDifferentConnection =\n !state.connectionParams ||\n state.connectionParams.replicaId !== replicaId ||\n state.connectionParams.sessionId !== sessionId\n\n if (isDifferentConnection) {\n clearPresignedUrl()\n }\n\n connectionAttemptCounter.current += 1\n const attemptId = connectionAttemptCounter.current\n\n dispatch({\n type: 'CONNECT_REQUESTED',\n payload: { replicaId, sessionId, attemptId },\n })\n },\n [\n dispatch,\n state.connectionParams,\n resetEstablishWebsocketConnection,\n clearPresignedUrl,\n connectionAttemptCounter,\n ],\n )\n\n /**\n * Establish the WebSocket connection when conditions are met.\n * Uses the current model state at connection time for reconnections to the same session.\n * Note: Changes to `model` alone do NOT trigger reconnection - only changes to connection\n * params, visibility, or connection status will trigger a new connection attempt.\n */\n useEffect(() => {\n // Don't attempt connection if conditions aren't met\n const { connectionParams, connectionAttemptId } = state\n\n if (\n !connectionParams ||\n connectionAttemptId === null ||\n state.isConnected ||\n state.isConnecting ||\n isEstablishingWebsocketConnection ||\n errorEstablishingWebsocketConnection ||\n state.connectionError ||\n !isDocumentVisible\n ) {\n return\n }\n\n activeConnectionAttemptIdRef.current = connectionAttemptId\n\n // Use current model state for reconnections to same session\n // (model may have been created by a previous connection)\n establishWebsocketConnection({\n replicaId: connectionParams.replicaId,\n sessionId: connectionParams.sessionId,\n websocketOptions: {\n ...websocketOptionsWithoutModel,\n model: state.model, // Current model at connection time\n },\n })\n .then(ws => {\n if (activeConnectionAttemptIdRef.current !== connectionAttemptId) {\n ws.disconnect()\n return\n }\n\n dispatch({ type: 'CONNECTION_ESTABLISHED', payload: ws })\n })\n .catch(err => {\n dispatch({ type: 'CONNECTION_ERROR', payload: err })\n console.error('Failed to establish WebSocket', err)\n })\n }, [\n state,\n state.connectionParams,\n state.connectionAttemptId,\n state.isConnected,\n state.isConnecting,\n isEstablishingWebsocketConnection,\n errorEstablishingWebsocketConnection,\n isDocumentVisible,\n establishWebsocketConnection,\n websocketOptionsWithoutModel,\n ])\n\n const previousConnectionParams =\n useRef<WebSocketState['connectionParams']>(null)\n\n useEffect(() => {\n const previous = previousConnectionParams.current\n const current = state.connectionParams\n\n if (\n previous &&\n current &&\n (previous.replicaId !== current.replicaId ||\n previous.sessionId !== current.sessionId)\n ) {\n state.websocketInstance?.disconnect()\n }\n\n previousConnectionParams.current = current\n }, [state.connectionParams, state.websocketInstance])\n\n useEffect(() => {\n return () => {\n state.websocketInstance?.disconnect()\n activeConnectionAttemptIdRef.current = null\n }\n }, [state.websocketInstance])\n\n /**\n * Checks if the model snapshot contains the minimum data required for rendering (columns and rows).\n */\n function isModelRenderable(model: GridModel | null) {\n if (!model || !model.api.getSnapshot() || !modelSnapshot) {\n return false\n }\n const { columnNames, columnOrder, rows } = modelSnapshot\n const columnsReady = columnNames.length >= 1\n const orderReady = columnOrder.length >= 1\n const rowsReady = rows.length >= 0\n return columnsReady && orderReady && rowsReady\n }\n\n return {\n isConnected: state.isConnected,\n websocketInstance: state.websocketInstance,\n hasCompletedInitialSync: state.hasCompletedInitialSync,\n isSyncing: state.isSyncing,\n model: state.model,\n modelSnapshot,\n connect,\n presignedUrl,\n errorEstablishingWebsocketConnection:\n state.connectionError ?? errorEstablishingWebsocketConnection,\n websocketError: state.websocketError,\n hasSufficientData: isModelRenderable(state.model),\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useDataGridWebsocket.js","names":["GridModel","useCRDTModelView","normalizeWebsocketError","useCallback","useEffect","useMemo","useReducer","useRef","DataGridWebSocket","useEstablishWebsocketConnection","useDocumentVisibility","WebSocketState","model","hasCompletedInitialSync","isSyncing","isConnected","isConnecting","connectionParams","replicaId","sessionId","websocketInstance","connectionAttemptId","connectionError","websocketError","WebSocketAction","type","payload","attemptId","websocketReducer","state","action","isSameConnection","initialWebSocketState","UseDataGridWebSocketOptions","onGridReady","onReplicaConnected","onReplicaDisconnected","useDataGridWebSocket","options","dispatch","connectionAttemptCounter","activeConnectionAttemptIdRef","modelSnapshot","isDocumentVisible","mutateAsync","establishWebsocketConnection","isPending","isEstablishingWebsocketConnection","error","errorEstablishingWebsocketConnection","presignedUrl","reset","resetEstablishWebsocketConnection","clearPresignedUrl","handleModelCreate","newModel","websocketOptionsWithoutModel","onStatusChange","open","onModelCreate","onSyncStart","onSyncEnd","onError","connect","isDifferentConnection","current","websocketOptions","then","ws","disconnect","catch","err","console","previousConnectionParams","previous","isModelRenderable","api","getSnapshot","columnNames","columnOrder","rows","columnsReady","length","orderReady","rowsReady","hasSufficientData"],"sources":["../../../src/components/DataGrid/useDataGridWebsocket.ts"],"sourcesContent":["import { GridModel } from '@/components/DataGrid/DataGridTypes'\nimport { useCRDTModelView } from '@/components/DataGrid/useCRDTModelView'\nimport { normalizeWebsocketError } from '@/components/DataGrid/utils/normalizeWebsocketError'\nimport { useCallback, useEffect, useMemo, useReducer, useRef } from 'react'\nimport { DataGridWebSocket } from './DataGridWebSocket'\nimport { useEstablishWebsocketConnection } from '@/synapse-queries/grid/useEstablishWebsocketConnection'\nimport { useDocumentVisibility } from '@react-hookz/web'\n\n// State type\ninterface WebSocketState {\n model: GridModel | null\n /**\n * True if the WebSocket has finished the initial sync and can process CRDT updates.\n * Corresponds to the `GRID_READY` action.\n */\n hasCompletedInitialSync: boolean\n /**\n * True while a clock-sync exchange is in progress. Set on every outgoing\n * `synchronize-clock` and cleared on `ResponseComplete`, which the server\n * sends once per exchange to signal \"we're synchronized\" — not per request.\n */\n isSyncing: boolean\n isConnected: boolean\n isConnecting: boolean\n connectionParams: {\n replicaId: number\n sessionId: string\n } | null\n websocketInstance: DataGridWebSocket | null\n connectionAttemptId: number | null\n connectionError: unknown\n websocketError: unknown\n}\n\n// Action types\ntype WebSocketAction =\n | {\n type: 'CONNECT_REQUESTED'\n payload: { replicaId: number; sessionId: string; attemptId: number }\n }\n | { type: 'CONNECTION_ESTABLISHED'; payload: DataGridWebSocket }\n | { type: 'CONNECTION_OPENED' }\n | { type: 'CONNECTION_CLOSED' }\n | { type: 'GRID_READY' }\n | { type: 'SYNC_STARTED' }\n | { type: 'SYNC_ENDED' }\n | { type: 'MODEL_CREATED'; payload: GridModel }\n | { type: 'CONNECTION_ERROR'; payload: unknown }\n | { type: 'WEBSOCKET_ERROR'; payload: unknown }\n\n// Reducer function\nfunction websocketReducer(\n state: WebSocketState,\n action: WebSocketAction,\n): WebSocketState {\n switch (action.type) {\n case 'CONNECT_REQUESTED': {\n const isSameConnection =\n state.connectionParams &&\n state.connectionParams.replicaId === action.payload.replicaId &&\n state.connectionParams.sessionId === action.payload.sessionId\n\n return {\n ...state,\n connectionParams: {\n replicaId: action.payload.replicaId,\n sessionId: action.payload.sessionId,\n },\n hasCompletedInitialSync: isSameConnection\n ? state.hasCompletedInitialSync\n : false,\n isSyncing: false,\n model: isSameConnection ? state.model : null,\n isConnected: false,\n isConnecting: false,\n connectionAttemptId: action.payload.attemptId,\n connectionError: null,\n }\n }\n\n case 'CONNECTION_ESTABLISHED':\n return {\n ...state,\n websocketInstance: action.payload,\n isConnecting: true,\n }\n\n case 'CONNECTION_OPENED':\n return {\n ...state,\n isConnected: true,\n isConnecting: false,\n }\n\n case 'CONNECTION_CLOSED':\n return {\n ...state,\n isConnected: false,\n isConnecting: false,\n isSyncing: false,\n }\n\n case 'GRID_READY':\n return {\n ...state,\n hasCompletedInitialSync: true,\n }\n\n case 'SYNC_STARTED':\n return {\n ...state,\n isSyncing: true,\n }\n\n case 'SYNC_ENDED':\n return {\n ...state,\n isSyncing: false,\n }\n\n case 'MODEL_CREATED':\n return {\n ...state,\n model: action.payload,\n }\n\n case 'CONNECTION_ERROR':\n return {\n ...state,\n connectionError: action.payload,\n isConnecting: false,\n }\n\n case 'WEBSOCKET_ERROR':\n return {\n ...state,\n websocketError: action.payload,\n }\n\n default:\n return state\n }\n}\n\nexport const initialWebSocketState: WebSocketState = {\n model: null,\n hasCompletedInitialSync: false,\n isSyncing: false,\n isConnected: false,\n isConnecting: false,\n connectionParams: null,\n websocketInstance: null,\n connectionAttemptId: null,\n connectionError: null,\n websocketError: null,\n}\n\n/**\n * Custom hook to manage a DataGrid WebSocket connection.\n * Handles:\n * - Fetching presigned URLs via a mutation hook\n * - Instantiating the DataGridWebSocket\n * - Connection status tracking\n * - Reconnection on disconnect\n * - Grid model updates and snapshot tracking\n */\nexport interface UseDataGridWebSocketOptions {\n onGridReady?: () => void\n onReplicaConnected?: () => void\n onReplicaDisconnected?: () => void\n}\n\nexport function useDataGridWebSocket(options?: UseDataGridWebSocketOptions) {\n const [state, dispatch] = useReducer(websocketReducer, initialWebSocketState)\n\n const connectionAttemptCounter = useRef(0)\n const activeConnectionAttemptIdRef = useRef<number | null>(null)\n\n const modelSnapshot = useCRDTModelView(state.model)\n\n const isDocumentVisible = useDocumentVisibility()\n\n const {\n mutateAsync: establishWebsocketConnection,\n isPending: isEstablishingWebsocketConnection,\n error: errorEstablishingWebsocketConnection,\n presignedUrl,\n reset: resetEstablishWebsocketConnection,\n clearPresignedUrl,\n } = useEstablishWebsocketConnection()\n\n // Update model creation handler - only set model, don't reset to null on disconnect\n const handleModelCreate = useCallback(\n (newModel: GridModel) => {\n dispatch({ type: 'MODEL_CREATED', payload: newModel })\n },\n [dispatch],\n )\n\n // Memoize websocket options to prevent unnecessary re-renders (excluding model to avoid circular deps)\n const websocketOptionsWithoutModel = useMemo(\n () => ({\n onGridReady: () => {\n dispatch({ type: 'GRID_READY' })\n options?.onGridReady?.()\n },\n onStatusChange: (open: boolean) =>\n dispatch({ type: open ? 'CONNECTION_OPENED' : 'CONNECTION_CLOSED' }),\n onModelCreate: handleModelCreate,\n onReplicaConnected: options?.onReplicaConnected,\n onReplicaDisconnected: options?.onReplicaDisconnected,\n onSyncStart: () => dispatch({ type: 'SYNC_STARTED' }),\n onSyncEnd: () => dispatch({ type: 'SYNC_ENDED' }),\n onError: (error: unknown) =>\n dispatch({\n type: 'WEBSOCKET_ERROR',\n payload: normalizeWebsocketError(error),\n }),\n }),\n [\n handleModelCreate,\n options?.onGridReady,\n options?.onReplicaConnected,\n options?.onReplicaDisconnected,\n ],\n )\n\n // Initiate (or re-initiate) a connection\n const connect = useCallback(\n (replicaId: number, sessionId: string) => {\n resetEstablishWebsocketConnection()\n\n const isDifferentConnection =\n !state.connectionParams ||\n state.connectionParams.replicaId !== replicaId ||\n state.connectionParams.sessionId !== sessionId\n\n if (isDifferentConnection) {\n clearPresignedUrl()\n }\n\n connectionAttemptCounter.current += 1\n const attemptId = connectionAttemptCounter.current\n\n dispatch({\n type: 'CONNECT_REQUESTED',\n payload: { replicaId, sessionId, attemptId },\n })\n },\n [\n dispatch,\n state.connectionParams,\n resetEstablishWebsocketConnection,\n clearPresignedUrl,\n connectionAttemptCounter,\n ],\n )\n\n /**\n * Establish the WebSocket connection when conditions are met.\n * Uses the current model state at connection time for reconnections to the same session.\n * Note: Changes to `model` alone do NOT trigger reconnection - only changes to connection\n * params, visibility, or connection status will trigger a new connection attempt.\n */\n useEffect(() => {\n // Don't attempt connection if conditions aren't met\n const { connectionParams, connectionAttemptId } = state\n\n if (\n !connectionParams ||\n connectionAttemptId === null ||\n state.isConnected ||\n state.isConnecting ||\n isEstablishingWebsocketConnection ||\n errorEstablishingWebsocketConnection ||\n state.connectionError ||\n !isDocumentVisible\n ) {\n return\n }\n\n activeConnectionAttemptIdRef.current = connectionAttemptId\n\n // Use current model state for reconnections to same session\n // (model may have been created by a previous connection)\n establishWebsocketConnection({\n replicaId: connectionParams.replicaId,\n sessionId: connectionParams.sessionId,\n websocketOptions: {\n ...websocketOptionsWithoutModel,\n model: state.model, // Current model at connection time\n },\n })\n .then(ws => {\n if (activeConnectionAttemptIdRef.current !== connectionAttemptId) {\n ws.disconnect()\n return\n }\n\n dispatch({ type: 'CONNECTION_ESTABLISHED', payload: ws })\n })\n .catch(err => {\n dispatch({ type: 'CONNECTION_ERROR', payload: err })\n console.error('Failed to establish WebSocket', err)\n })\n }, [\n state,\n state.connectionParams,\n state.connectionAttemptId,\n state.isConnected,\n state.isConnecting,\n isEstablishingWebsocketConnection,\n errorEstablishingWebsocketConnection,\n isDocumentVisible,\n establishWebsocketConnection,\n websocketOptionsWithoutModel,\n ])\n\n const previousConnectionParams =\n useRef<WebSocketState['connectionParams']>(null)\n\n useEffect(() => {\n const previous = previousConnectionParams.current\n const current = state.connectionParams\n\n if (\n previous &&\n current &&\n (previous.replicaId !== current.replicaId ||\n previous.sessionId !== current.sessionId)\n ) {\n state.websocketInstance?.disconnect()\n }\n\n previousConnectionParams.current = current\n }, [state.connectionParams, state.websocketInstance])\n\n useEffect(() => {\n return () => {\n state.websocketInstance?.disconnect()\n activeConnectionAttemptIdRef.current = null\n }\n }, [state.websocketInstance])\n\n /**\n * Checks if the model snapshot contains the minimum data required for rendering (columns and rows).\n */\n function isModelRenderable(model: GridModel | null) {\n if (!model || !model.api.getSnapshot() || !modelSnapshot) {\n return false\n }\n const { columnNames, columnOrder, rows } = modelSnapshot\n const columnsReady = columnNames.length >= 1\n const orderReady = columnOrder.length >= 1\n const rowsReady = rows.length >= 0\n return columnsReady && orderReady && rowsReady\n }\n\n return {\n isConnected: state.isConnected,\n websocketInstance: state.websocketInstance,\n hasCompletedInitialSync: state.hasCompletedInitialSync,\n isSyncing: state.isSyncing,\n model: state.model,\n modelSnapshot,\n connect,\n presignedUrl,\n errorEstablishingWebsocketConnection:\n state.connectionError ?? errorEstablishingWebsocketConnection,\n websocketError: state.websocketError,\n hasSufficientData: isModelRenderable(state.model),\n }\n}\n"],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@ type ColumnConfig = {
|
|
|
13
13
|
showPinIcon?: boolean;
|
|
14
14
|
isPinned?: boolean;
|
|
15
15
|
onTogglePin?: () => void;
|
|
16
|
+
isUpsertKey?: boolean;
|
|
16
17
|
/**
|
|
17
18
|
* Optional column-level schema info. When provided, paste behavior coerces
|
|
18
19
|
* empty pasted cells to the schema-correct blank (undefined for optional
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"columnFactory.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/utils/columnFactory.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAA;AAC7E,OAAO,EAGL,MAAM,EAIP,MAAM,wCAAwC,CAAA;AAuE/C,KAAK,YAAY,GAAG;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,gBAAgB,EAAE,eAAe,EAAE,GAAG,MAAM,EAAE,GAAG,IAAI,CAAA;IACrD,UAAU,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;CACxC,CAAA;
|
|
1
|
+
{"version":3,"file":"columnFactory.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/utils/columnFactory.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAA;AAC7E,OAAO,EAGL,MAAM,EAIP,MAAM,wCAAwC,CAAA;AAuE/C,KAAK,YAAY,GAAG;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,gBAAgB,EAAE,eAAe,EAAE,GAAG,MAAM,EAAE,GAAG,IAAI,CAAA;IACrD,UAAU,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;CACxC,CAAA;AAgMD,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAGzD"}
|
|
@@ -53,8 +53,8 @@ function g(e, t) {
|
|
|
53
53
|
}
|
|
54
54
|
return n.displayName = `CellWithTooltip(${t})`, n;
|
|
55
55
|
}
|
|
56
|
-
function _(e) {
|
|
57
|
-
return e ? "header-cell-required" : "header-cell";
|
|
56
|
+
function _(e, t) {
|
|
57
|
+
return t ? "header-upsert-key" : e ? "header-cell-required" : "header-cell";
|
|
58
58
|
}
|
|
59
59
|
function v(e, t) {
|
|
60
60
|
return ({ rowData: n }) => ({
|
|
@@ -80,11 +80,12 @@ function b(e, t) {
|
|
|
80
80
|
name: e.columnName,
|
|
81
81
|
description: e.description,
|
|
82
82
|
isRequired: e.isRequired,
|
|
83
|
+
isUpsertKey: e.isUpsertKey,
|
|
83
84
|
showPinIcon: e.showPinIcon,
|
|
84
85
|
isPinned: e.isPinned,
|
|
85
86
|
onTogglePin: e.onTogglePin
|
|
86
87
|
}),
|
|
87
|
-
headerClassName: _(e.isRequired),
|
|
88
|
+
headerClassName: _(e.isRequired, !!e.isUpsertKey),
|
|
88
89
|
minWidth: a,
|
|
89
90
|
basis: a,
|
|
90
91
|
grow: 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"columnFactory.js","names":["dateTimeColumn","EnumeratedValue","FlatTypeInfo","SchemaPropertyInfo","CellComponent","CellProps","Column","createTextColumn","floatColumn","keyColumn","autocompleteColumn","autocompleteMultipleEnumColumn","calculateDefaultColumnWidth","HeaderOptions","ColumnHeaderWithTooltip","Tooltip","SmartToyTwoTone","DataGridRow","wrapPasteValueWithSchemaCoercion","getEmptyValue","withChangeIndicatorTooltip","OriginalComponent","T","C","colName","CellWithTooltip","props","$","_c","changeInfo","rowData","__cellChangeInfo","isAgent","category","t0","t1","tooltipText","position","top","right","width","height","zIndex","pointerEvents","t2","focus","fontSize","alignSelf","flexShrink","mr","color","backgroundColor","t3","displayName","ColumnConfig","columnName","description","disabled","typeInfo","enumeratedValues","isRequired","customWidth","showPinIcon","isPinned","onTogglePin","schemaPropertyInfo","getHeaderClassName","createDeleteValue","Record","createParseUserInput","value","trimmedValue","trim","createBaseColumn","config","columnImpl","headerOptions","hasDescription","undefined","keyed","component","title","headerClassName","minWidth","basis","grow","shrink","deleteValue","pasteValue","stickyLeft","COLUMN_FACTORIES","multipleEnum","choices","colType","type","limitTags","clearValue","boolean","number","enumerated","date-time","text","continuousUpdates","deletedValue","parseUserInput","cellClassName","getColumnType","length","format","isArray","createColumn","columnType"],"sources":["../../../../src/components/DataGrid/utils/columnFactory.tsx"],"sourcesContent":["import { dateTimeColumn } from '@/components/DataGrid/columns/DateTimeColumn'\nimport { EnumeratedValue } from '@/utils/jsonschema/getEnumeratedValues'\nimport { FlatTypeInfo } from '@/utils/jsonschema/getType'\nimport { SchemaPropertyInfo } from '@/utils/jsonschema/getSchemaPropertyInfo'\nimport {\n CellComponent,\n CellProps,\n Column,\n createTextColumn,\n floatColumn,\n keyColumn,\n} from '@sage-bionetworks/react-datasheet-grid'\nimport { autocompleteColumn } from '../columns/AutocompleteColumn'\nimport { autocompleteMultipleEnumColumn } from '../columns/AutocompleteMultipleEnumColumn'\nimport {\n calculateDefaultColumnWidth,\n HeaderOptions,\n} from './calculateColumnWidth'\nimport { ColumnHeaderWithTooltip } from '../components/ColumnHeaderWithTooltip'\nimport { Tooltip } from '@mui/material'\nimport { SmartToyTwoTone } from '@mui/icons-material'\nimport type { DataGridRow } from '../DataGridTypes'\nimport { wrapPasteValueWithSchemaCoercion } from './schemaAwarePasteValue'\nimport { getEmptyValue } from './getEmptyValue'\n\n/**\n * Wraps a column cell component to overlay change-attribution indicators:\n * - Non-agent changes: invisible 7×7px tooltip trigger over the CSS triangle (top-right).\n * - Agent changes: robot icon (1em, vertically centered on the right) with no triangle.\n */\nfunction withChangeIndicatorTooltip<T, C>(\n OriginalComponent: CellComponent<T, C>,\n colName: string,\n): CellComponent<T, C> {\n function CellWithTooltip(props: CellProps<T, C>) {\n const changeInfo = (props.rowData as DataGridRow).__cellChangeInfo?.[\n colName\n ]\n const isAgent =\n changeInfo?.category === 'own-agent' ||\n changeInfo?.category === 'other-agent'\n return (\n <>\n <OriginalComponent {...props} />\n {changeInfo && !isAgent && (\n <Tooltip title={changeInfo.tooltipText} placement=\"top-end\">\n <div\n style={{\n position: 'absolute',\n top: 0,\n right: 0,\n width: 7,\n height: 7,\n zIndex: 21,\n pointerEvents: 'auto',\n }}\n />\n </Tooltip>\n )}\n {isAgent && !props.focus && (\n <Tooltip title={changeInfo.tooltipText} placement=\"left\">\n <SmartToyTwoTone\n sx={{\n fontSize: '1em',\n alignSelf: 'center',\n flexShrink: 0,\n mr: 0.5,\n zIndex: 21,\n pointerEvents: 'auto',\n color: 'grey.400',\n backgroundColor: 'transparent',\n }}\n />\n </Tooltip>\n )}\n </>\n )\n }\n CellWithTooltip.displayName = `CellWithTooltip(${colName})`\n return CellWithTooltip\n}\n\ntype ColumnConfig = {\n columnName: string\n description?: string\n disabled?: boolean\n typeInfo: FlatTypeInfo | null\n enumeratedValues: EnumeratedValue[] | string[] | null\n isRequired: boolean\n customWidth?: number\n showPinIcon?: boolean\n isPinned?: boolean\n onTogglePin?: () => void\n /**\n * Optional column-level schema info. When provided, paste behavior coerces\n * empty pasted cells to the schema-correct blank (undefined for optional\n * columns, null for required columns). Omit to preserve the column impl's\n * default paste behavior.\n */\n schemaPropertyInfo?: SchemaPropertyInfo\n}\n\nfunction getHeaderClassName(isRequired: boolean): string {\n return isRequired ? 'header-cell-required' : 'header-cell'\n}\n\nfunction createDeleteValue(columnName: string, isRequired?: boolean) {\n return ({ rowData }: { rowData: Record<string, unknown> }) => ({\n ...rowData,\n [columnName]: getEmptyValue(isRequired),\n })\n}\n\nfunction createParseUserInput(isRequired?: boolean) {\n return (value: string) => {\n const trimmedValue = value.trim()\n if (trimmedValue === '') {\n return getEmptyValue(isRequired)\n }\n return trimmedValue\n }\n}\n\nfunction createBaseColumn(config: ColumnConfig, columnImpl: any) {\n const headerOptions: HeaderOptions = {\n showPinIcon: config.showPinIcon,\n hasDescription: !!config.description,\n }\n\n const width =\n config.customWidth ??\n calculateDefaultColumnWidth(\n config.columnName,\n undefined, // propertyInfo is not available here, passed from higher level\n headerOptions,\n )\n\n const keyed = keyColumn(config.columnName, columnImpl)\n return {\n ...keyed,\n component: withChangeIndicatorTooltip(keyed.component!, config.columnName),\n title: (\n <ColumnHeaderWithTooltip\n name={config.columnName}\n description={config.description}\n isRequired={config.isRequired}\n showPinIcon={config.showPinIcon}\n isPinned={config.isPinned}\n onTogglePin={config.onTogglePin}\n />\n ),\n headerClassName: getHeaderClassName(config.isRequired),\n minWidth: width,\n basis: width,\n grow: 0,\n shrink: 0,\n disabled: config.disabled,\n deleteValue: createDeleteValue(config.columnName, config.isRequired),\n pasteValue: wrapPasteValueWithSchemaCoercion(\n keyed.pasteValue,\n config.columnName,\n config.schemaPropertyInfo,\n ),\n stickyLeft: config.isPinned,\n }\n}\n\nconst COLUMN_FACTORIES = {\n multipleEnum: (config: ColumnConfig) => {\n return createBaseColumn(\n config,\n autocompleteMultipleEnumColumn({\n choices: config.enumeratedValues ?? [],\n colType: config.typeInfo?.type || null,\n limitTags: 3,\n clearValue: getEmptyValue(config.isRequired),\n }),\n )\n },\n\n boolean: (config: ColumnConfig) => {\n return createBaseColumn(\n config,\n autocompleteColumn({\n choices: [true, false],\n colType: 'boolean',\n clearValue: getEmptyValue(config.isRequired),\n }),\n )\n },\n\n number: (config: ColumnConfig) => {\n return createBaseColumn(config, floatColumn)\n },\n\n enumerated: (config: ColumnConfig) => {\n return createBaseColumn(\n config,\n autocompleteColumn({\n choices: config.enumeratedValues ?? [],\n colType: config.typeInfo?.type || null,\n clearValue: getEmptyValue(config.isRequired),\n }),\n )\n },\n\n 'date-time': (config: ColumnConfig) => {\n const columnImpl = dateTimeColumn({\n colType: config.typeInfo?.type || null,\n })\n\n // Date-time needs special width calculation\n const headerOptions: HeaderOptions = {\n showPinIcon: config.showPinIcon,\n hasDescription: !!config.description,\n }\n\n const width =\n config.customWidth ??\n calculateDefaultColumnWidth(\n config.columnName,\n {\n type: config.typeInfo ?? undefined,\n isRequired: config.isRequired,\n enumeratedValues: null,\n },\n headerOptions,\n )\n\n return {\n ...createBaseColumn(config, columnImpl),\n minWidth: width,\n basis: width,\n }\n },\n\n text: (config: ColumnConfig) => {\n const columnImpl = createTextColumn({\n continuousUpdates: false,\n deletedValue: undefined,\n parseUserInput: createParseUserInput(config.isRequired),\n })\n\n return {\n ...createBaseColumn(config, columnImpl),\n cellClassName: 'MuiInputBase-input',\n }\n },\n}\n\nfunction getColumnType(\n typeInfo: FlatTypeInfo | null,\n enumeratedValues?: EnumeratedValue[] | string[] | null,\n): keyof typeof COLUMN_FACTORIES {\n if (!typeInfo) {\n return enumeratedValues && enumeratedValues.length > 0\n ? 'enumerated'\n : 'text'\n }\n\n if (typeInfo.format === 'date-time') {\n return 'date-time'\n }\n\n // Handle arrays - check if it's an array of enums\n if (typeInfo.isArray) {\n return 'multipleEnum'\n }\n\n if (typeInfo.type === 'boolean') {\n return 'boolean'\n }\n\n if (typeInfo.type === 'number' || typeInfo.type === 'integer') {\n return 'number'\n }\n\n if (enumeratedValues && enumeratedValues.length > 0) {\n return 'enumerated'\n }\n\n return 'text'\n}\n\nexport function createColumn(config: ColumnConfig): Column {\n const columnType = getColumnType(config.typeInfo, config.enumeratedValues)\n return COLUMN_FACTORIES[columnType](config)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"columnFactory.js","names":["dateTimeColumn","EnumeratedValue","FlatTypeInfo","SchemaPropertyInfo","CellComponent","CellProps","Column","createTextColumn","floatColumn","keyColumn","autocompleteColumn","autocompleteMultipleEnumColumn","calculateDefaultColumnWidth","HeaderOptions","ColumnHeaderWithTooltip","Tooltip","SmartToyTwoTone","DataGridRow","wrapPasteValueWithSchemaCoercion","getEmptyValue","withChangeIndicatorTooltip","OriginalComponent","T","C","colName","CellWithTooltip","props","$","_c","changeInfo","rowData","__cellChangeInfo","isAgent","category","t0","t1","tooltipText","position","top","right","width","height","zIndex","pointerEvents","t2","focus","fontSize","alignSelf","flexShrink","mr","color","backgroundColor","t3","displayName","ColumnConfig","columnName","description","disabled","typeInfo","enumeratedValues","isRequired","customWidth","showPinIcon","isPinned","onTogglePin","isUpsertKey","schemaPropertyInfo","getHeaderClassName","createDeleteValue","Record","createParseUserInput","value","trimmedValue","trim","createBaseColumn","config","columnImpl","headerOptions","hasDescription","undefined","keyed","component","title","headerClassName","minWidth","basis","grow","shrink","deleteValue","pasteValue","stickyLeft","COLUMN_FACTORIES","multipleEnum","choices","colType","type","limitTags","clearValue","boolean","number","enumerated","date-time","text","continuousUpdates","deletedValue","parseUserInput","cellClassName","getColumnType","length","format","isArray","createColumn","columnType"],"sources":["../../../../src/components/DataGrid/utils/columnFactory.tsx"],"sourcesContent":["import { dateTimeColumn } from '@/components/DataGrid/columns/DateTimeColumn'\nimport { EnumeratedValue } from '@/utils/jsonschema/getEnumeratedValues'\nimport { FlatTypeInfo } from '@/utils/jsonschema/getType'\nimport { SchemaPropertyInfo } from '@/utils/jsonschema/getSchemaPropertyInfo'\nimport {\n CellComponent,\n CellProps,\n Column,\n createTextColumn,\n floatColumn,\n keyColumn,\n} from '@sage-bionetworks/react-datasheet-grid'\nimport { autocompleteColumn } from '../columns/AutocompleteColumn'\nimport { autocompleteMultipleEnumColumn } from '../columns/AutocompleteMultipleEnumColumn'\nimport {\n calculateDefaultColumnWidth,\n HeaderOptions,\n} from './calculateColumnWidth'\nimport { ColumnHeaderWithTooltip } from '../components/ColumnHeaderWithTooltip'\nimport { Tooltip } from '@mui/material'\nimport { SmartToyTwoTone } from '@mui/icons-material'\nimport type { DataGridRow } from '../DataGridTypes'\nimport { wrapPasteValueWithSchemaCoercion } from './schemaAwarePasteValue'\nimport { getEmptyValue } from './getEmptyValue'\n\n/**\n * Wraps a column cell component to overlay change-attribution indicators:\n * - Non-agent changes: invisible 7×7px tooltip trigger over the CSS triangle (top-right).\n * - Agent changes: robot icon (1em, vertically centered on the right) with no triangle.\n */\nfunction withChangeIndicatorTooltip<T, C>(\n OriginalComponent: CellComponent<T, C>,\n colName: string,\n): CellComponent<T, C> {\n function CellWithTooltip(props: CellProps<T, C>) {\n const changeInfo = (props.rowData as DataGridRow).__cellChangeInfo?.[\n colName\n ]\n const isAgent =\n changeInfo?.category === 'own-agent' ||\n changeInfo?.category === 'other-agent'\n return (\n <>\n <OriginalComponent {...props} />\n {changeInfo && !isAgent && (\n <Tooltip title={changeInfo.tooltipText} placement=\"top-end\">\n <div\n style={{\n position: 'absolute',\n top: 0,\n right: 0,\n width: 7,\n height: 7,\n zIndex: 21,\n pointerEvents: 'auto',\n }}\n />\n </Tooltip>\n )}\n {isAgent && !props.focus && (\n <Tooltip title={changeInfo.tooltipText} placement=\"left\">\n <SmartToyTwoTone\n sx={{\n fontSize: '1em',\n alignSelf: 'center',\n flexShrink: 0,\n mr: 0.5,\n zIndex: 21,\n pointerEvents: 'auto',\n color: 'grey.400',\n backgroundColor: 'transparent',\n }}\n />\n </Tooltip>\n )}\n </>\n )\n }\n CellWithTooltip.displayName = `CellWithTooltip(${colName})`\n return CellWithTooltip\n}\n\ntype ColumnConfig = {\n columnName: string\n description?: string\n disabled?: boolean\n typeInfo: FlatTypeInfo | null\n enumeratedValues: EnumeratedValue[] | string[] | null\n isRequired: boolean\n customWidth?: number\n showPinIcon?: boolean\n isPinned?: boolean\n onTogglePin?: () => void\n isUpsertKey?: boolean\n /**\n * Optional column-level schema info. When provided, paste behavior coerces\n * empty pasted cells to the schema-correct blank (undefined for optional\n * columns, null for required columns). Omit to preserve the column impl's\n * default paste behavior.\n */\n schemaPropertyInfo?: SchemaPropertyInfo\n}\n\nfunction getHeaderClassName(isRequired: boolean, isUpsertKey: boolean): string {\n return isUpsertKey\n ? 'header-upsert-key'\n : isRequired\n ? 'header-cell-required'\n : 'header-cell'\n}\n\nfunction createDeleteValue(columnName: string, isRequired?: boolean) {\n return ({ rowData }: { rowData: Record<string, unknown> }) => ({\n ...rowData,\n [columnName]: getEmptyValue(isRequired),\n })\n}\n\nfunction createParseUserInput(isRequired?: boolean) {\n return (value: string) => {\n const trimmedValue = value.trim()\n if (trimmedValue === '') {\n return getEmptyValue(isRequired)\n }\n return trimmedValue\n }\n}\n\nfunction createBaseColumn(config: ColumnConfig, columnImpl: any) {\n const headerOptions: HeaderOptions = {\n showPinIcon: config.showPinIcon,\n hasDescription: !!config.description,\n }\n\n const width =\n config.customWidth ??\n calculateDefaultColumnWidth(\n config.columnName,\n undefined, // propertyInfo is not available here, passed from higher level\n headerOptions,\n )\n\n const keyed = keyColumn(config.columnName, columnImpl)\n return {\n ...keyed,\n component: withChangeIndicatorTooltip(keyed.component!, config.columnName),\n title: (\n <ColumnHeaderWithTooltip\n name={config.columnName}\n description={config.description}\n isRequired={config.isRequired}\n isUpsertKey={config.isUpsertKey}\n showPinIcon={config.showPinIcon}\n isPinned={config.isPinned}\n onTogglePin={config.onTogglePin}\n />\n ),\n headerClassName: getHeaderClassName(\n config.isRequired,\n !!config.isUpsertKey,\n ),\n minWidth: width,\n basis: width,\n grow: 0,\n shrink: 0,\n disabled: config.disabled,\n deleteValue: createDeleteValue(config.columnName, config.isRequired),\n pasteValue: wrapPasteValueWithSchemaCoercion(\n keyed.pasteValue,\n config.columnName,\n config.schemaPropertyInfo,\n ),\n stickyLeft: config.isPinned,\n }\n}\n\nconst COLUMN_FACTORIES = {\n multipleEnum: (config: ColumnConfig) => {\n return createBaseColumn(\n config,\n autocompleteMultipleEnumColumn({\n choices: config.enumeratedValues ?? [],\n colType: config.typeInfo?.type || null,\n limitTags: 3,\n clearValue: getEmptyValue(config.isRequired),\n }),\n )\n },\n\n boolean: (config: ColumnConfig) => {\n return createBaseColumn(\n config,\n autocompleteColumn({\n choices: [true, false],\n colType: 'boolean',\n clearValue: getEmptyValue(config.isRequired),\n }),\n )\n },\n\n number: (config: ColumnConfig) => {\n return createBaseColumn(config, floatColumn)\n },\n\n enumerated: (config: ColumnConfig) => {\n return createBaseColumn(\n config,\n autocompleteColumn({\n choices: config.enumeratedValues ?? [],\n colType: config.typeInfo?.type || null,\n clearValue: getEmptyValue(config.isRequired),\n }),\n )\n },\n\n 'date-time': (config: ColumnConfig) => {\n const columnImpl = dateTimeColumn({\n colType: config.typeInfo?.type || null,\n })\n\n // Date-time needs special width calculation\n const headerOptions: HeaderOptions = {\n showPinIcon: config.showPinIcon,\n hasDescription: !!config.description,\n }\n\n const width =\n config.customWidth ??\n calculateDefaultColumnWidth(\n config.columnName,\n {\n type: config.typeInfo ?? undefined,\n isRequired: config.isRequired,\n enumeratedValues: null,\n },\n headerOptions,\n )\n\n return {\n ...createBaseColumn(config, columnImpl),\n minWidth: width,\n basis: width,\n }\n },\n\n text: (config: ColumnConfig) => {\n const columnImpl = createTextColumn({\n continuousUpdates: false,\n deletedValue: undefined,\n parseUserInput: createParseUserInput(config.isRequired),\n })\n\n return {\n ...createBaseColumn(config, columnImpl),\n cellClassName: 'MuiInputBase-input',\n }\n },\n}\n\nfunction getColumnType(\n typeInfo: FlatTypeInfo | null,\n enumeratedValues?: EnumeratedValue[] | string[] | null,\n): keyof typeof COLUMN_FACTORIES {\n if (!typeInfo) {\n return enumeratedValues && enumeratedValues.length > 0\n ? 'enumerated'\n : 'text'\n }\n\n if (typeInfo.format === 'date-time') {\n return 'date-time'\n }\n\n // Handle arrays - check if it's an array of enums\n if (typeInfo.isArray) {\n return 'multipleEnum'\n }\n\n if (typeInfo.type === 'boolean') {\n return 'boolean'\n }\n\n if (typeInfo.type === 'number' || typeInfo.type === 'integer') {\n return 'number'\n }\n\n if (enumeratedValues && enumeratedValues.length > 0) {\n return 'enumerated'\n }\n\n return 'text'\n}\n\nexport function createColumn(config: ColumnConfig): Column {\n const columnType = getColumnType(config.typeInfo, config.enumeratedValues)\n return COLUMN_FACTORIES[columnType](config)\n}\n"],"mappings":";;;;;;;;;;;;;AA8BA,SAASoB,EACPC,GACAG,GACqB;CACrB,SAAAC,EAAAC,GAAA;EAAA,IAAAC,IAAAC,EAAA,EAAA,GACEC,IAAoBH,EAAKI,QAAuBC,mBAC9CP,IAEFQ,IACEH,GAAUI,aAAe,eACzBJ,GAAUI,aAAe,eAAaC;EAAA,AAAAP,EAAA,OAAAD,IAGJQ,IAAAP,EAAA,MAAhCO,IAAA,kBAAC,GAAD,EAAkB,GAAKR,EAAK,CAAA,GAAIC,EAAA,KAAAD,GAAAC,EAAA,KAAAO;EAAA,IAAAC;EAAA,AAAAR,EAAA,OAAAE,KAAAF,EAAA,OAAAK,KAC/BG,IAAAN,KAAA,CAAeG,KACd,kBAAC,GAAD;GAAgB,OAAAH,EAAUO;GAAwB,WAAA;aAChD,kBAAA,OAAA,EACS,OAAA;IAAAC,UACK;IAAUC,KACf;IAACC,OACC;IAACC,OACD;IAACC,QACA;IAACC,QACD;IAAEC,eACK;GACjB,EAAC,CAAA;EAVG,CAAA,GAaThB,EAAA,KAAAE,GAAAF,EAAA,KAAAK,GAAAL,EAAA,KAAAQ,KAAAA,IAAAR,EAAA;EAAA,IAAAiB;EAAA,AAAAjB,EAAA,OAAAE,KAAAF,EAAA,OAAAK,KAAAL,EAAA,OAAAD,EAAAmB,SACAD,IAAAZ,KAAA,CAAYN,EAAKmB,SAChB,kBAAC,GAAD;GAAgB,OAAAhB,EAAUO;GAAwB,WAAA;aAChD,kBAAC,GAAD,EACM,IAAA;IAAAU,UACQ;IAAKC,WACJ;IAAQC,YACP;IAACC,IACT;IAAGP,QACC;IAAEC,eACK;IAAMO,OACd;IAAUC,iBACA;GACnB,EAAC,CAAA;EAXG,CAAA,GAcTxB,EAAA,KAAAE,GAAAF,EAAA,KAAAK,GAAAL,EAAA,KAAAD,EAAAmB,OAAAlB,EAAA,KAAAiB,KAAAA,IAAAjB,EAAA;EAAA,IAAAyB;EACA,OADAzB,EAAA,OAAAO,KAAAP,EAAA,QAAAQ,KAAAR,EAAA,QAAAiB,KAhCHQ,IAAA,kBAAA,GAAA,EAAA,UAAA;GACElB;GACCC;GAeAS;EAeA,EAAA,CAAA,GACAjB,EAAA,KAAAO,GAAAP,EAAA,MAAAQ,GAAAR,EAAA,MAAAiB,GAAAjB,EAAA,MAAAyB,KAAAA,IAAAzB,EAAA,KAjCHyB;CAiCG;CAIP,OADA3B,EAAgB4B,cAAc,mBAAmB7B,EAAO,IACjDC;AACT;AAuBA,SAAS0C,EAAmBP,GAAqBK,GAA8B;CAC7E,OAAOA,IACH,sBACAL,IACE,yBACA;AACR;AAEA,SAASQ,EAAkBb,GAAoBK,GAAsB;CACnE,QAAQ,EAAE9B,kBAAqD;EAC7D,GAAGA;GACFyB,IAAapC,EAAcyC,CAAU;CACxC;AACF;AAEA,SAASU,EAAqBV,GAAsB;CAClD,QAAQW,MAAkB;EACxB,IAAMC,IAAeD,EAAME,KAAK;EAIhC,OAHID,MAAiB,KACZrD,EAAcyC,CAAU,IAE1BY;CACT;AACF;AAEA,SAASE,EAAiBC,GAAsBC,GAAiB;CAC/D,IAAMC,IAA+B;EACnCf,aAAaa,EAAOb;EACpBgB,gBAAgB,CAAC,CAACH,EAAOnB;CAC3B,GAEMhB,IACJmC,EAAOd,eACPjD,EACE+D,EAAOpB,YACPwB,KAAAA,GACAF,CACF,GAEIG,IAAQvE,EAAUkE,EAAOpB,YAAYqB,CAAU;CACrD,OAAO;EACL,GAAGI;EACHC,WAAW7D,EAA2B4D,EAAMC,WAAYN,EAAOpB,UAAU;EACzE2B,OACE,kBAAC,GAAD;GACE,MAAMP,EAAOpB;GACb,aAAaoB,EAAOnB;GACpB,YAAYmB,EAAOf;GACnB,aAAae,EAAOV;GACpB,aAAaU,EAAOb;GACpB,UAAUa,EAAOZ;GACjB,aAAaY,EAAOX;EAAY,CAAA;EAGpCmB,iBAAiBhB,EACfQ,EAAOf,YACP,CAAC,CAACe,EAAOV,WACX;EACAmB,UAAU5C;EACV6C,OAAO7C;EACP8C,MAAM;EACNC,QAAQ;EACR9B,UAAUkB,EAAOlB;EACjB+B,aAAapB,EAAkBO,EAAOpB,YAAYoB,EAAOf,UAAU;EACnE6B,YAAYvE,EACV8D,EAAMS,YACNd,EAAOpB,YACPoB,EAAOT,kBACT;EACAwB,YAAYf,EAAOZ;CACrB;AACF;AAEA,IAAM4B,IAAmB;CACvBC,eAAejB,MACND,EACLC,GACAhE,EAA+B;EAC7BkF,SAASlB,EAAOhB,oBAAoB,CAAA;EACpCmC,SAASnB,EAAOjB,UAAUqC,QAAQ;EAClCC,WAAW;EACXC,YAAY9E,EAAcwD,EAAOf,UAAU;CAC7C,CAAC,CACH;CAGFsC,UAAUvB,MACDD,EACLC,GACAjE,EAAmB;EACjBmF,SAAS,CAAC,IAAM,EAAK;EACrBC,SAAS;EACTG,YAAY9E,EAAcwD,EAAOf,UAAU;CAC7C,CAAC,CACH;CAGFuC,SAASxB,MACAD,EAAiBC,GAAQnE,CAAW;CAG7C4F,aAAazB,MACJD,EACLC,GACAjE,EAAmB;EACjBmF,SAASlB,EAAOhB,oBAAoB,CAAA;EACpCmC,SAASnB,EAAOjB,UAAUqC,QAAQ;EAClCE,YAAY9E,EAAcwD,EAAOf,UAAU;CAC7C,CAAC,CACH;CAGF,cAAce,MAAyB;EACrC,IAAMC,IAAa5E,EAAe,EAChC8F,SAASnB,EAAOjB,UAAUqC,QAAQ,KACpC,CAAC,GAGKlB,IAA+B;GACnCf,aAAaa,EAAOb;GACpBgB,gBAAgB,CAAC,CAACH,EAAOnB;EAC3B,GAEMhB,IACJmC,EAAOd,eACPjD,EACE+D,EAAOpB,YACP;GACEwC,MAAMpB,EAAOjB,YAAYqB,KAAAA;GACzBnB,YAAYe,EAAOf;GACnBD,kBAAkB;EACpB,GACAkB,CACF;EAEF,OAAO;GACL,GAAGH,EAAiBC,GAAQC,CAAU;GACtCQ,UAAU5C;GACV6C,OAAO7C;EACT;CACF;CAEA8D,OAAO3B,OAOE;EACL,GAAGD,EAAiBC,GAPHpE,EAAiB;GAClCgG,mBAAmB;GACnBC,cAAczB,KAAAA;GACd0B,gBAAgBnC,EAAqBK,EAAOf,UAAU;EACxD,CAG8BgB,CAAU;EACtC8B,eAAe;CACjB;AAEJ;AAEA,SAASC,EACPjD,GACAC,GAC+B;CA4B/B,OA3BKD,IAMDA,EAASmD,WAAW,cACf,cAILnD,EAASoD,UACJ,iBAGLpD,EAASqC,SAAS,YACb,YAGLrC,EAASqC,SAAS,YAAYrC,EAASqC,SAAS,YAC3C,WAGLpC,KAAoBA,EAAiBiD,SAAS,IACzC,eAGF,SA1BEjD,KAAoBA,EAAiBiD,SAAS,IACjD,eACA;AAyBR;AAEA,SAAgBG,EAAapC,GAA8B;CAEzD,OAAOgB,EADYgB,EAAchC,EAAOjB,UAAUiB,EAAOhB,gBACjCqD,GAAYrC,CAAM;AAC5C"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Column } from '@sage-bionetworks/react-datasheet-grid';
|
|
2
2
|
import { SchemaPropertiesMap } from '@/utils/jsonschema/getSchemaPropertyInfo';
|
|
3
|
-
export declare function modelColsToGrid(columnNames: string[], columnOrder: number[], schemaPropertiesInfo: SchemaPropertiesMap, columnWidths?: Record<string, number>, pinnedColumns?: Set<number>, onTogglePin?: (columnIndex: number) => void): Column[];
|
|
3
|
+
export declare function modelColsToGrid(columnNames: string[], columnOrder: number[], schemaPropertiesInfo: SchemaPropertiesMap, columnWidths?: Record<string, number>, pinnedColumns?: Set<number>, onTogglePin?: (columnIndex: number) => void, upsertKey?: string[]): Column[];
|
|
4
4
|
//# sourceMappingURL=modelColsToGrid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modelColsToGrid.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/utils/modelColsToGrid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wCAAwC,CAAA;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAE9E,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,MAAM,EAAE,EACrB,oBAAoB,EAAE,mBAAmB,EACzC,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACzC,aAAa,GAAE,GAAG,CAAC,MAAM,CAAa,EACtC,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"modelColsToGrid.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/utils/modelColsToGrid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wCAAwC,CAAA;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAE9E,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,MAAM,EAAE,EACrB,oBAAoB,EAAE,mBAAmB,EACzC,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACzC,aAAa,GAAE,GAAG,CAAC,MAAM,CAAa,EACtC,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,EAC3C,SAAS,CAAC,EAAE,MAAM,EAAE,GACnB,MAAM,EAAE,CAwBV"}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { createColumn as e } from "./columnFactory.js";
|
|
2
2
|
//#region src/components/DataGrid/utils/modelColsToGrid.ts
|
|
3
|
-
function t(t, n, r, i = {}, a = /* @__PURE__ */ new Set(), o) {
|
|
4
|
-
return n.map((n,
|
|
5
|
-
let
|
|
3
|
+
function t(t, n, r, i = {}, a = /* @__PURE__ */ new Set(), o, s) {
|
|
4
|
+
return n.map((n, c) => {
|
|
5
|
+
let l = t[n], u = r[l], d = c === 0 && o !== void 0, f = a.has(c);
|
|
6
6
|
return e({
|
|
7
|
-
columnName:
|
|
8
|
-
description:
|
|
9
|
-
typeInfo:
|
|
10
|
-
enumeratedValues:
|
|
11
|
-
isRequired:
|
|
12
|
-
disabled:
|
|
13
|
-
customWidth: i[
|
|
14
|
-
showPinIcon:
|
|
15
|
-
isPinned:
|
|
16
|
-
onTogglePin: o ? () => o(
|
|
17
|
-
schemaPropertyInfo:
|
|
7
|
+
columnName: l,
|
|
8
|
+
description: u?.description,
|
|
9
|
+
typeInfo: u?.type || null,
|
|
10
|
+
enumeratedValues: u?.enumeratedValues || [],
|
|
11
|
+
isRequired: u?.isRequired || !1,
|
|
12
|
+
disabled: u?.type?.readOnly,
|
|
13
|
+
customWidth: i[l],
|
|
14
|
+
showPinIcon: d,
|
|
15
|
+
isPinned: f,
|
|
16
|
+
onTogglePin: o ? () => o(c) : void 0,
|
|
17
|
+
schemaPropertyInfo: u,
|
|
18
|
+
isUpsertKey: s?.includes(l) ?? !1
|
|
18
19
|
});
|
|
19
20
|
});
|
|
20
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modelColsToGrid.js","names":["Column","createColumn","SchemaPropertiesMap","modelColsToGrid","columnNames","columnOrder","schemaPropertiesInfo","columnWidths","Record","pinnedColumns","Set","onTogglePin","columnIndex","map","index","arrayIndex","columnName","propertyInfo","showPinIcon","undefined","isPinned","has","description","typeInfo","type","enumeratedValues","isRequired","disabled","readOnly","customWidth","schemaPropertyInfo"],"sources":["../../../../src/components/DataGrid/utils/modelColsToGrid.ts"],"sourcesContent":["import { Column } from '@sage-bionetworks/react-datasheet-grid'\nimport { createColumn } from './columnFactory'\nimport { SchemaPropertiesMap } from '@/utils/jsonschema/getSchemaPropertyInfo'\n\nexport function modelColsToGrid(\n columnNames: string[],\n columnOrder: number[],\n schemaPropertiesInfo: SchemaPropertiesMap,\n columnWidths: Record<string, number> = {},\n pinnedColumns: Set<number> = new Set(),\n onTogglePin?: (columnIndex: number) => void,\n): Column[] {\n return columnOrder.map((index: number, arrayIndex: number) => {\n const columnName = columnNames[index]\n const propertyInfo = schemaPropertiesInfo[columnName]\n\n // Only show pin functionality for the first column and when toggle handler exists\n const showPinIcon = arrayIndex === 0 && onTogglePin !== undefined\n const isPinned = pinnedColumns.has(arrayIndex)\n\n return createColumn({\n columnName,\n description: propertyInfo?.description,\n typeInfo: propertyInfo?.type || null,\n enumeratedValues: propertyInfo?.enumeratedValues || [],\n isRequired: propertyInfo?.isRequired || false,\n disabled: propertyInfo?.type?.readOnly,\n customWidth: columnWidths[columnName],\n showPinIcon,\n isPinned,\n onTogglePin: onTogglePin ? () => onTogglePin(arrayIndex) : undefined,\n schemaPropertyInfo: propertyInfo,\n })\n })\n}\n"],"mappings":";;AAIA,SAAgBG,EACdC,GACAC,GACAC,GACAC,IAAuC,CAAC,GACxCE,oBAA6B,IAAIC,IAAI,GACrCC,GACU;CACV,
|
|
1
|
+
{"version":3,"file":"modelColsToGrid.js","names":["Column","createColumn","SchemaPropertiesMap","modelColsToGrid","columnNames","columnOrder","schemaPropertiesInfo","columnWidths","Record","pinnedColumns","Set","onTogglePin","columnIndex","upsertKey","map","index","arrayIndex","columnName","propertyInfo","showPinIcon","undefined","isPinned","has","description","typeInfo","type","enumeratedValues","isRequired","disabled","readOnly","customWidth","schemaPropertyInfo","isUpsertKey","includes"],"sources":["../../../../src/components/DataGrid/utils/modelColsToGrid.ts"],"sourcesContent":["import { Column } from '@sage-bionetworks/react-datasheet-grid'\nimport { createColumn } from './columnFactory'\nimport { SchemaPropertiesMap } from '@/utils/jsonschema/getSchemaPropertyInfo'\n\nexport function modelColsToGrid(\n columnNames: string[],\n columnOrder: number[],\n schemaPropertiesInfo: SchemaPropertiesMap,\n columnWidths: Record<string, number> = {},\n pinnedColumns: Set<number> = new Set(),\n onTogglePin?: (columnIndex: number) => void,\n upsertKey?: string[],\n): Column[] {\n return columnOrder.map((index: number, arrayIndex: number) => {\n const columnName = columnNames[index]\n const propertyInfo = schemaPropertiesInfo[columnName]\n\n // Only show pin functionality for the first column and when toggle handler exists\n const showPinIcon = arrayIndex === 0 && onTogglePin !== undefined\n const isPinned = pinnedColumns.has(arrayIndex)\n\n return createColumn({\n columnName,\n description: propertyInfo?.description,\n typeInfo: propertyInfo?.type || null,\n enumeratedValues: propertyInfo?.enumeratedValues || [],\n isRequired: propertyInfo?.isRequired || false,\n disabled: propertyInfo?.type?.readOnly,\n customWidth: columnWidths[columnName],\n showPinIcon,\n isPinned,\n onTogglePin: onTogglePin ? () => onTogglePin(arrayIndex) : undefined,\n schemaPropertyInfo: propertyInfo,\n isUpsertKey: upsertKey?.includes(columnName) ?? false,\n })\n })\n}\n"],"mappings":";;AAIA,SAAgBG,EACdC,GACAC,GACAC,GACAC,IAAuC,CAAC,GACxCE,oBAA6B,IAAIC,IAAI,GACrCC,GACAE,GACU;CACV,OAAOR,EAAYS,KAAKC,GAAeC,MAAuB;EAC5D,IAAMC,IAAab,EAAYW,IACzBG,IAAeZ,EAAqBW,IAGpCE,IAAcH,MAAe,KAAKL,MAAgBS,KAAAA,GAClDC,IAAWZ,EAAca,IAAIN,CAAU;EAE7C,OAAOf,EAAa;GAClBgB;GACAM,aAAaL,GAAcK;GAC3BC,UAAUN,GAAcO,QAAQ;GAChCC,kBAAkBR,GAAcQ,oBAAoB,CAAA;GACpDC,YAAYT,GAAcS,cAAc;GACxCC,UAAUV,GAAcO,MAAMI;GAC9BC,aAAavB,EAAaU;GAC1BE;GACAE;GACAV,aAAaA,UAAoBA,EAAYK,CAAU,IAAII,KAAAA;GAC3DW,oBAAoBb;GACpBc,aAAanB,GAAWoB,SAAShB,CAAU,KAAK;EAClD,CAAC;CACH,CAAC;AACH"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server sends error notifications as plain objects `{message, code, errno}`.
|
|
3
|
+
* Convert those to proper Error instances so error boundaries can render the message.
|
|
4
|
+
* Non-conforming values are returned unchanged.
|
|
5
|
+
*/
|
|
6
|
+
export declare function normalizeWebsocketError(error: unknown): unknown;
|
|
7
|
+
//# sourceMappingURL=normalizeWebsocketError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizeWebsocketError.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/utils/normalizeWebsocketError.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAU/D"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/components/DataGrid/utils/normalizeWebsocketError.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
return typeof e == "object" && e && "message" in e && typeof e.message == "string" ? Error(e.message) : e;
|
|
4
|
+
}
|
|
5
|
+
//#endregion
|
|
6
|
+
export { e as normalizeWebsocketError };
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=normalizeWebsocketError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizeWebsocketError.js","names":["normalizeWebsocketError","error","message","Error"],"sources":["../../../../src/components/DataGrid/utils/normalizeWebsocketError.ts"],"sourcesContent":["/**\n * The server sends error notifications as plain objects `{message, code, errno}`.\n * Convert those to proper Error instances so error boundaries can render the message.\n * Non-conforming values are returned unchanged.\n */\nexport function normalizeWebsocketError(error: unknown): unknown {\n if (\n error != null &&\n typeof error === 'object' &&\n 'message' in error &&\n typeof (error as { message: unknown }).message === 'string'\n ) {\n return new Error((error as { message: string }).message)\n }\n return error\n}\n"],"mappings":";AAKA,SAAgBA,EAAwBC,GAAyB;CAS/D,OANE,OAAOA,KAAU,YADjBA,KAEA,aAAaA,KACb,OAAQA,EAA+BC,WAAY,WAExCC,MAAOF,EAA8BC,OAAO,IAElDD;AACT"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { QueryBundleRequest } from '@sage-bionetworks/synapse-types';
|
|
2
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
1
3
|
export type GoalsProps = {
|
|
2
4
|
entityId: string;
|
|
3
5
|
isAssetIcon?: boolean;
|
|
@@ -13,6 +15,12 @@ export type GoalsDataProps = {
|
|
|
13
15
|
isAssetIcon: boolean;
|
|
14
16
|
linkText?: string;
|
|
15
17
|
};
|
|
18
|
+
export declare function buildGoalsQueryBundleRequest(entityId: string): QueryBundleRequest;
|
|
16
19
|
export declare function Goals(props: GoalsProps): import("react/jsx-runtime").JSX.Element;
|
|
17
20
|
export default Goals;
|
|
21
|
+
/**
|
|
22
|
+
* Prefetches the Goals table query into a QueryClient for use with HydrationBoundary.
|
|
23
|
+
* Uses anonymous access; warm-caches for unauthenticated users.
|
|
24
|
+
*/
|
|
25
|
+
export declare function prefetchGoals(queryClient: QueryClient, entityId: string): Promise<void>;
|
|
18
26
|
//# sourceMappingURL=Goals.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Goals.d.ts","sourceRoot":"","sources":["../../../src/components/Goals/Goals.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Goals.d.ts","sourceRoot":"","sources":["../../../src/components/Goals/Goals.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAOnD,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAcD,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,GACf,kBAAkB,CAapB;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,2CAwHtC;AACD,eAAe,KAAK,CAAA;AAEpB;;;GAGG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -1,53 +1,59 @@
|
|
|
1
1
|
import "../../utils/SynapseConstants.js";
|
|
2
|
-
import
|
|
3
|
-
import t from "
|
|
2
|
+
import e from "../../synapse-client/index.js";
|
|
3
|
+
import { ErrorBanner as t } from "../error/ErrorBanner.js";
|
|
4
|
+
import { KeyFactory as n } from "../../synapse-queries/KeyFactory.js";
|
|
5
|
+
import r from "../../utils/hooks/useShowDesktop.js";
|
|
4
6
|
import "../../utils/index.js";
|
|
5
|
-
import { getFieldIndex as
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import { useMemo as
|
|
11
|
-
import { Box as
|
|
12
|
-
import { Fragment as
|
|
7
|
+
import { getFieldIndex as i } from "../../utils/functions/queryUtils.js";
|
|
8
|
+
import a, { tableQueryUseQueryDefaults as o } from "../../synapse-queries/entity/useGetQueryResultBundle.js";
|
|
9
|
+
import s from "../../utils/hooks/useGetGoalData.js";
|
|
10
|
+
import c from "./Goals.Desktop.js";
|
|
11
|
+
import l from "./Goals.Mobile.js";
|
|
12
|
+
import { useMemo as u } from "react";
|
|
13
|
+
import { Box as d } from "@mui/material";
|
|
14
|
+
import { Fragment as f, jsx as p } from "react/jsx-runtime";
|
|
13
15
|
//#region src/components/Goals/Goals.tsx
|
|
14
|
-
var
|
|
15
|
-
function
|
|
16
|
-
|
|
16
|
+
var m = 1200;
|
|
17
|
+
function h(e) {
|
|
18
|
+
return {
|
|
17
19
|
concreteType: "org.sagebionetworks.repo.model.table.QueryBundleRequest",
|
|
18
|
-
entityId:
|
|
20
|
+
entityId: e,
|
|
19
21
|
partMask: 5,
|
|
20
22
|
query: { sql: `select *
|
|
21
|
-
from ${
|
|
23
|
+
from ${e}
|
|
22
24
|
order by ItemOrder` }
|
|
23
|
-
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function g(e) {
|
|
28
|
+
let { entityId: n, isAssetIcon: o = !1, linkText: g, itemsPerRow: _ = 3 } = e, v = r(m), { data: y } = a(h(n)), { assets: b, error: x } = s(n, y), S = i("TableId", y), C = i("CountSql", y), w = i("Title", y), T = i("Summary", y), E = i("Link", y), D = u(() => y?.queryResult.queryResults.rows.map((e, t) => {
|
|
24
29
|
let n = e.values;
|
|
25
30
|
n.some((e) => e === null) && console.warn("Row has null value(s) when no nulls expected");
|
|
26
|
-
let r =
|
|
27
|
-
|
|
28
|
-
let a = n[
|
|
31
|
+
let r = S > -1 ? n[S] : void 0, i;
|
|
32
|
+
C > -1 && n[C] ? i = n[C] : r && (i = `SELECT * FROM ${r}`);
|
|
33
|
+
let a = n[w], s = n[T], c = n[E], l = b?.[t] ?? "";
|
|
29
34
|
return {
|
|
30
35
|
countSql: i,
|
|
31
36
|
title: a,
|
|
32
|
-
summary:
|
|
33
|
-
link:
|
|
34
|
-
asset:
|
|
35
|
-
isAssetIcon:
|
|
37
|
+
summary: s,
|
|
38
|
+
link: c,
|
|
39
|
+
asset: l,
|
|
40
|
+
isAssetIcon: o
|
|
36
41
|
};
|
|
37
42
|
}), [
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
C,
|
|
44
|
+
b,
|
|
45
|
+
o,
|
|
46
|
+
E,
|
|
47
|
+
y?.queryResult,
|
|
40
48
|
T,
|
|
41
|
-
|
|
42
|
-
w
|
|
43
|
-
x,
|
|
44
|
-
C
|
|
49
|
+
S,
|
|
50
|
+
w
|
|
45
51
|
]);
|
|
46
|
-
if (
|
|
47
|
-
if (!
|
|
48
|
-
if (
|
|
49
|
-
let e = `calc((100% - ${
|
|
50
|
-
return /* @__PURE__ */
|
|
52
|
+
if (x) return /* @__PURE__ */ p(t, { error: x });
|
|
53
|
+
if (!D) return /* @__PURE__ */ p(f, {});
|
|
54
|
+
if (v) {
|
|
55
|
+
let e = `calc((100% - ${_ * 20 + (_ - 1) * 7}px) / ${_} - 0.5px)`;
|
|
56
|
+
return /* @__PURE__ */ p(d, {
|
|
51
57
|
className: "Goals",
|
|
52
58
|
sx: {
|
|
53
59
|
display: "flex",
|
|
@@ -56,21 +62,29 @@ function f(f) {
|
|
|
56
62
|
justifyContent: "center",
|
|
57
63
|
alignItems: "stretch"
|
|
58
64
|
},
|
|
59
|
-
children:
|
|
65
|
+
children: D.map((t, n) => /* @__PURE__ */ p(c, {
|
|
60
66
|
...t,
|
|
61
|
-
linkText:
|
|
67
|
+
linkText: g,
|
|
62
68
|
cardWidth: e
|
|
63
69
|
}, n))
|
|
64
70
|
});
|
|
65
|
-
} else return /* @__PURE__ */
|
|
71
|
+
} else return /* @__PURE__ */ p("div", {
|
|
66
72
|
className: "Goals",
|
|
67
|
-
children:
|
|
73
|
+
children: D.map((e, t) => /* @__PURE__ */ p(l, {
|
|
68
74
|
...e,
|
|
69
|
-
linkText:
|
|
75
|
+
linkText: g
|
|
70
76
|
}, t))
|
|
71
77
|
});
|
|
72
78
|
}
|
|
79
|
+
async function _(t, r) {
|
|
80
|
+
let i = new n(void 0), a = h(r);
|
|
81
|
+
await t.prefetchQuery({
|
|
82
|
+
...o,
|
|
83
|
+
queryKey: i.getEntityTableQueryResultQueryKey(a, !1),
|
|
84
|
+
queryFn: () => e.getQueryTableResults(a, void 0)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
73
87
|
//#endregion
|
|
74
|
-
export {
|
|
88
|
+
export { g as Goals, g as default, h as buildGoalsQueryBundleRequest, _ as prefetchGoals };
|
|
75
89
|
|
|
76
90
|
//# sourceMappingURL=Goals.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Goals.js","names":[],"sources":["../../../src/components/Goals/Goals.tsx"],"sourcesContent":["import useGetQueryResultBundle from '@/synapse-queries/entity/useGetQueryResultBundle'\nimport { SynapseConstants } from '@/utils'\nimport { getFieldIndex } from '@/utils/functions/queryUtils'\nimport useGetGoalData from '@/utils/hooks/useGetGoalData'\nimport useShowDesktop from '@/utils/hooks/useShowDesktop'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { useMemo } from 'react'\nimport { ErrorBanner } from '../error/ErrorBanner'\nimport GoalsDesktop from './Goals.Desktop'\nimport GoalsMobile from './Goals.Mobile'\nimport { Box } from '@mui/material'\n\nexport type GoalsProps = {\n entityId: string\n isAssetIcon?: boolean // If true, the asset will be used as an icon instead of a background image.\n linkText?: string\n itemsPerRow?: number\n}\n\nexport type GoalsDataProps = {\n countSql?: string\n title: string\n summary: string\n link: string\n asset: string\n isAssetIcon: boolean\n linkText?: string\n}\n\nenum ExpectedColumns {\n TABLEID = 'TableId', // Both TableId or CountSql are used to indicate what Table rows to count.\n COUNT_SQL = 'CountSql', // Code uses CountSql over TableId if defined (if the CountSql column is in the schema and filled in).\n TITLE = 'Title',\n SUMMARY = 'Summary',\n LINK = 'Link',\n ASSET = 'Asset',\n}\n\n// PORTALS-2367\nconst GOALS_DESKTOP_MIN_BREAKPOINT = 1200\n\nexport function
|
|
1
|
+
{"version":3,"file":"Goals.js","names":[],"sources":["../../../src/components/Goals/Goals.tsx"],"sourcesContent":["import SynapseClient from '@/synapse-client'\nimport useGetQueryResultBundle, {\n tableQueryUseQueryDefaults,\n} from '@/synapse-queries/entity/useGetQueryResultBundle'\nimport { KeyFactory } from '@/synapse-queries/KeyFactory'\nimport { SynapseConstants } from '@/utils'\nimport { getFieldIndex } from '@/utils/functions/queryUtils'\nimport useGetGoalData from '@/utils/hooks/useGetGoalData'\nimport useShowDesktop from '@/utils/hooks/useShowDesktop'\nimport { QueryBundleRequest } from '@sage-bionetworks/synapse-types'\nimport { QueryClient } from '@tanstack/react-query'\nimport { useMemo } from 'react'\nimport { ErrorBanner } from '../error/ErrorBanner'\nimport GoalsDesktop from './Goals.Desktop'\nimport GoalsMobile from './Goals.Mobile'\nimport { Box } from '@mui/material'\n\nexport type GoalsProps = {\n entityId: string\n isAssetIcon?: boolean // If true, the asset will be used as an icon instead of a background image.\n linkText?: string\n itemsPerRow?: number\n}\n\nexport type GoalsDataProps = {\n countSql?: string\n title: string\n summary: string\n link: string\n asset: string\n isAssetIcon: boolean\n linkText?: string\n}\n\nenum ExpectedColumns {\n TABLEID = 'TableId', // Both TableId or CountSql are used to indicate what Table rows to count.\n COUNT_SQL = 'CountSql', // Code uses CountSql over TableId if defined (if the CountSql column is in the schema and filled in).\n TITLE = 'Title',\n SUMMARY = 'Summary',\n LINK = 'Link',\n ASSET = 'Asset',\n}\n\n// PORTALS-2367\nconst GOALS_DESKTOP_MIN_BREAKPOINT = 1200\n\nexport function buildGoalsQueryBundleRequest(\n entityId: string,\n): QueryBundleRequest {\n return {\n concreteType: 'org.sagebionetworks.repo.model.table.QueryBundleRequest',\n entityId,\n partMask:\n SynapseConstants.BUNDLE_MASK_QUERY_SELECT_COLUMNS |\n SynapseConstants.BUNDLE_MASK_QUERY_RESULTS,\n query: {\n sql: `select *\n from ${entityId}\n order by ItemOrder`,\n },\n }\n}\n\nexport function Goals(props: GoalsProps) {\n const { entityId, isAssetIcon = false, linkText, itemsPerRow = 3 } = props\n const showDesktop = useShowDesktop(GOALS_DESKTOP_MIN_BREAKPOINT)\n const queryBundleRequest = buildGoalsQueryBundleRequest(entityId)\n const { data: queryResultBundle } =\n useGetQueryResultBundle(queryBundleRequest)\n\n const { assets: goalAssets, error: goalError } = useGetGoalData(\n entityId,\n queryResultBundle,\n )\n\n const tableIdColumnIndex = getFieldIndex(\n ExpectedColumns.TABLEID,\n queryResultBundle,\n )\n const countSqlColumnIndex = getFieldIndex(\n ExpectedColumns.COUNT_SQL,\n queryResultBundle,\n )\n\n const titleColumnIndex = getFieldIndex(\n ExpectedColumns.TITLE,\n queryResultBundle,\n )\n const summaryColumnIndex = getFieldIndex(\n ExpectedColumns.SUMMARY,\n queryResultBundle,\n )\n const linkColumnIndex = getFieldIndex(ExpectedColumns.LINK, queryResultBundle)\n\n const goalsDataProps = useMemo(() => {\n return queryResultBundle?.queryResult!.queryResults.rows.map(\n (el, index): GoalsDataProps => {\n const values = el.values as string[]\n if (values.some(value => value === null)) {\n // We cast values above assuming there are no null values, emit a warning just in case.\n console.warn('Row has null value(s) when no nulls expected')\n }\n const tableId =\n tableIdColumnIndex > -1 ? values[tableIdColumnIndex] : undefined\n let countSql\n if (countSqlColumnIndex > -1 && values[countSqlColumnIndex]) {\n countSql = values[countSqlColumnIndex]\n } else if (tableId) {\n countSql = `SELECT * FROM ${tableId}`\n }\n const title = values[titleColumnIndex]\n const summary = values[summaryColumnIndex]\n const link = values[linkColumnIndex]\n // assume that we recieve assets in order of rows and there is an asset for each item\n // can revisit if this isn't the case.\n const asset = goalAssets?.[index] ?? ''\n return {\n countSql,\n title,\n summary,\n link,\n asset,\n isAssetIcon,\n }\n },\n )\n }, [\n countSqlColumnIndex,\n goalAssets,\n isAssetIcon,\n linkColumnIndex,\n queryResultBundle?.queryResult,\n summaryColumnIndex,\n tableIdColumnIndex,\n titleColumnIndex,\n ])\n\n if (goalError) {\n return <ErrorBanner error={goalError} />\n }\n\n if (!goalsDataProps) {\n return <></>\n }\n\n if (showDesktop) {\n // Each card has margin:10px (20px horizontal) from .Goals__Card CSS.\n // flex-basis must be the content width only; total row = N*(flex-basis+20) + (N-1)*gap.\n // Subtract 0.5px epsilon to absorb sub-pixel rounding and prevent wrapping.\n const horizontalMarginPerCard = 20\n const cardWidth = `calc((100% - ${\n itemsPerRow * horizontalMarginPerCard + (itemsPerRow - 1) * 7\n }px) / ${itemsPerRow} - 0.5px)`\n return (\n <Box\n className={`Goals`}\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '7px',\n justifyContent: 'center',\n alignItems: 'stretch',\n }}\n >\n {goalsDataProps.map((props, index) => (\n <GoalsDesktop\n key={index}\n {...props}\n linkText={linkText}\n cardWidth={cardWidth}\n />\n ))}\n </Box>\n )\n } else {\n return (\n <div className={`Goals`}>\n {goalsDataProps.map((props, index) => (\n <GoalsMobile key={index} {...props} linkText={linkText} />\n ))}\n </div>\n )\n }\n}\nexport default Goals\n\n/**\n * Prefetches the Goals table query into a QueryClient for use with HydrationBoundary.\n * Uses anonymous access; warm-caches for unauthenticated users.\n */\nexport async function prefetchGoals(\n queryClient: QueryClient,\n entityId: string,\n): Promise<void> {\n const keyFactory = new KeyFactory(undefined)\n const queryBundleRequest = buildGoalsQueryBundleRequest(entityId)\n await queryClient.prefetchQuery({\n ...tableQueryUseQueryDefaults,\n queryKey: keyFactory.getEntityTableQueryResultQueryKey(\n queryBundleRequest,\n false,\n ),\n queryFn: () =>\n SynapseClient.getQueryTableResults(queryBundleRequest, undefined),\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4CA,IAAM,IAA+B;AAErC,SAAgB,EACd,GACoB;CACpB,OAAO;EACL,cAAc;EACd;EACA,UACE;EAEF,OAAO,EACL,KAAK;mBACQ,EAAS;gCAExB;CACF;AACF;AAEA,SAAgB,EAAM,GAAmB;CACvC,IAAM,EAAE,aAAU,iBAAc,IAAO,aAAU,iBAAc,MAAM,GAC/D,IAAc,EAAe,CAA4B,GAEzD,EAAE,MAAM,MACZ,EAFyB,EAA6B,CAE9B,CAAkB,GAEtC,EAAE,QAAQ,GAAY,OAAO,MAAc,EAC/C,GACA,CACF,GAEM,IAAqB,EAAA,WAEzB,CACF,GACM,IAAsB,EAAA,YAE1B,CACF,GAEM,IAAmB,EAAA,SAEvB,CACF,GACM,IAAqB,EAAA,WAEzB,CACF,GACM,IAAkB,EAAA,QAAoC,CAAiB,GAEvE,IAAiB,QACd,GAAmB,YAAa,aAAa,KAAK,KACtD,GAAI,MAA0B;EAC7B,IAAM,IAAS,EAAG;EAClB,AAAI,EAAO,MAAK,MAAS,MAAU,IAAI,KAErC,QAAQ,KAAK,8CAA8C;EAE7D,IAAM,IACJ,IAAqB,KAAK,EAAO,KAAsB,KAAA,GACrD;EACJ,AAAI,IAAsB,MAAM,EAAO,KACrC,IAAW,EAAO,KACT,MACT,IAAW,iBAAiB;EAE9B,IAAM,IAAQ,EAAO,IACf,IAAU,EAAO,IACjB,IAAO,EAAO,IAGd,IAAQ,IAAa,MAAU;EACrC,OAAO;GACL;GACA;GACA;GACA;GACA;GACA;EACF;CACF,CACF,GACC;EACD;EACA;EACA;EACA;EACA,GAAmB;EACnB;EACA;EACA;CACF,CAAC;CAED,IAAI,GACF,OAAO,kBAAC,GAAD,EAAa,OAAO,EAAY,CAAA;CAGzC,IAAI,CAAC,GACH,OAAO,kBAAA,GAAA,CAAI,CAAA;CAGb,IAAI,GAAa;EAKf,IAAM,IAAY,gBAChB,IAAc,MAA2B,IAAc,KAAK,EAC7D,QAAQ,EAAY;EACrB,OACE,kBAAC,GAAD;GACE,WAAW;GACX,IAAI;IACF,SAAS;IACT,UAAU;IACV,KAAK;IACL,gBAAgB;IAChB,YAAY;GACd;aAEC,EAAe,KAAK,GAAO,MAC1B,kBAAC,GAAD;IAEE,GAAI;IACM;IACC;GACZ,GAJM,CAIN,CACF;EACE,CAAA;CAET,OACE,OACE,kBAAC,OAAD;EAAK,WAAW;YACb,EAAe,KAAK,GAAO,MAC1B,kBAAC,GAAD;GAAyB,GAAI;GAAiB;EAAW,GAAvC,CAAuC,CAC1D;CACE,CAAA;AAGX;AAOA,eAAsB,EACpB,GACA,GACe;CACf,IAAM,IAAa,IAAI,EAAW,KAAA,CAAS,GACrC,IAAqB,EAA6B,CAAQ;CAChE,MAAM,EAAY,cAAc;EAC9B,GAAG;EACH,UAAU,EAAW,kCACnB,GACA,EACF;EACA,eACE,EAAc,qBAAqB,GAAoB,KAAA,CAAS;CACpE,CAAC;AACH"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ProjectVisibility } from './getProjectVisibilityFromACL';
|
|
2
|
+
export type ProjectVisibilityChipProps = {
|
|
3
|
+
visibility: ProjectVisibility;
|
|
4
|
+
};
|
|
5
|
+
export type ProjectVisibilityChipContainerProps = {
|
|
6
|
+
entityId: string;
|
|
7
|
+
};
|
|
8
|
+
export default function ProjectVisibilityChip({ entityId, }: ProjectVisibilityChipContainerProps): import("react/jsx-runtime").JSX.Element | null;
|
|
9
|
+
//# sourceMappingURL=ProjectVisibilityChip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectVisibilityChip.d.ts","sourceRoot":"","sources":["../../../src/components/ProjectVisibilityChip/ProjectVisibilityChip.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,iBAAiB,EAClB,MAAM,+BAA+B,CAAA;AAKtC,MAAM,MAAM,0BAA0B,GAAG;IACvC,UAAU,EAAE,iBAAiB,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,mCAAmC,GAAG;IAChD,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AA+DD,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAC5C,QAAQ,GACT,EAAE,mCAAmC,kDA0BrC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useGetRealmPrincipals as e } from "../../synapse-queries/realm/useRealmPrincipals.js";
|
|
2
|
+
import t from "../../synapse-queries/entity/useEntityBundle.js";
|
|
3
|
+
import "../../synapse-queries/index.js";
|
|
4
|
+
import { getProjectVisibilityFromACL as n } from "./getProjectVisibilityFromACL.js";
|
|
5
|
+
import { Chip as r, Skeleton as i, Typography as a } from "@mui/material";
|
|
6
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
7
|
+
import s from "@mui/icons-material/VisibilityOutlined";
|
|
8
|
+
import c from "@mui/icons-material/LanguageOutlined";
|
|
9
|
+
import l from "@mui/icons-material/LockOutlined";
|
|
10
|
+
//#region src/components/ProjectVisibilityChip/ProjectVisibilityChip.tsx
|
|
11
|
+
var u = {
|
|
12
|
+
fill: "var(--synapse-gray-900)",
|
|
13
|
+
width: "16px"
|
|
14
|
+
}, d = {
|
|
15
|
+
PRIVATE: {
|
|
16
|
+
label: "Private Project",
|
|
17
|
+
color: "#FAC3C3",
|
|
18
|
+
icon: /* @__PURE__ */ o(l, { sx: u })
|
|
19
|
+
},
|
|
20
|
+
DISCOVERABLE: {
|
|
21
|
+
label: "Discoverable Project",
|
|
22
|
+
color: "#FDEFC1",
|
|
23
|
+
icon: /* @__PURE__ */ o(s, { sx: u })
|
|
24
|
+
},
|
|
25
|
+
PUBLIC: {
|
|
26
|
+
label: "Public Project",
|
|
27
|
+
color: "#D4EFD4",
|
|
28
|
+
icon: /* @__PURE__ */ o(c, { sx: u })
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
function f({ visibility: e }) {
|
|
32
|
+
return /* @__PURE__ */ o(r, {
|
|
33
|
+
sx: {
|
|
34
|
+
display: "flex",
|
|
35
|
+
padding: "4px 8px",
|
|
36
|
+
alignItems: "center",
|
|
37
|
+
gap: "6px",
|
|
38
|
+
borderRadius: "7px",
|
|
39
|
+
width: "fit-content",
|
|
40
|
+
backgroundColor: d[e].color,
|
|
41
|
+
"& .MuiChip-icon": {
|
|
42
|
+
marginLeft: "0px",
|
|
43
|
+
marginRight: "0px"
|
|
44
|
+
},
|
|
45
|
+
"& .MuiChip-label": { px: 0 }
|
|
46
|
+
},
|
|
47
|
+
icon: d[e].icon,
|
|
48
|
+
label: /* @__PURE__ */ o(a, {
|
|
49
|
+
variant: "body2",
|
|
50
|
+
sx: {
|
|
51
|
+
lineHeight: "12px",
|
|
52
|
+
letterSpacing: "-0.06px"
|
|
53
|
+
},
|
|
54
|
+
children: d[e].label
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function p({ entityId: r }) {
|
|
59
|
+
let { data: a, isLoading: s, isError: c } = t(r, void 0, { includeBenefactorACL: !0 }), { data: l, isLoading: u, isError: d } = e();
|
|
60
|
+
return c || d ? null : s || u ? /* @__PURE__ */ o(i, {
|
|
61
|
+
variant: "rounded",
|
|
62
|
+
width: 120,
|
|
63
|
+
height: 24
|
|
64
|
+
}) : /* @__PURE__ */ o(f, { visibility: n(a?.benefactorAcl?.resourceAccess ?? [], l || {}) });
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { p as default };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=ProjectVisibilityChip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectVisibilityChip.js","names":[],"sources":["../../../src/components/ProjectVisibilityChip/ProjectVisibilityChip.tsx"],"sourcesContent":["import { useGetRealmPrincipals } from '@/synapse-queries/realm/useRealmPrincipals'\nimport { Skeleton, Chip, Typography } from '@mui/material'\nimport { useGetEntityBundle } from '@/synapse-queries'\nimport {\n getProjectVisibilityFromACL,\n ProjectVisibility,\n} from './getProjectVisibilityFromACL'\nimport VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'\nimport LanguageOutlinedIcon from '@mui/icons-material/LanguageOutlined'\nimport LockOutlinedIcon from '@mui/icons-material/LockOutlined'\n\nexport type ProjectVisibilityChipProps = {\n visibility: ProjectVisibility\n}\n\nexport type ProjectVisibilityChipContainerProps = {\n entityId: string\n}\n\nconst iconStyles = {\n fill: 'var(--synapse-gray-900)',\n width: '16px',\n}\n\nconst VISIBILITY_LABELS: Record<\n ProjectVisibility,\n { label: string; color: string; icon: React.ReactElement }\n> = {\n PRIVATE: {\n label: 'Private Project',\n color: '#FAC3C3',\n icon: <LockOutlinedIcon sx={iconStyles} />,\n },\n DISCOVERABLE: {\n label: 'Discoverable Project',\n color: '#FDEFC1',\n icon: <VisibilityOutlinedIcon sx={iconStyles} />,\n },\n PUBLIC: {\n label: 'Public Project',\n color: '#D4EFD4',\n icon: <LanguageOutlinedIcon sx={iconStyles} />,\n },\n}\n\nfunction ProjectVisibilityChipUI({ visibility }: ProjectVisibilityChipProps) {\n return (\n <Chip\n sx={{\n display: 'flex',\n padding: '4px 8px',\n alignItems: 'center',\n gap: '6px',\n borderRadius: '7px',\n width: 'fit-content',\n backgroundColor: VISIBILITY_LABELS[visibility].color,\n '& .MuiChip-icon': {\n marginLeft: '0px',\n marginRight: '0px',\n },\n '& .MuiChip-label': {\n px: 0,\n },\n }}\n icon={VISIBILITY_LABELS[visibility].icon}\n label={\n <Typography\n variant=\"body2\"\n sx={{\n lineHeight: '12px',\n letterSpacing: '-0.06px',\n }}\n >\n {VISIBILITY_LABELS[visibility].label}\n </Typography>\n }\n />\n )\n}\n\nexport default function ProjectVisibilityChip({\n entityId,\n}: ProjectVisibilityChipContainerProps) {\n const {\n data: entityBundle,\n isLoading: isLoadingEntityBundle,\n isError: isErrorEntityBundle,\n } = useGetEntityBundle(entityId, undefined, { includeBenefactorACL: true })\n const {\n data: realmPrincipals,\n isLoading: isLoadingRealmPrincipals,\n isError: isErrorRealmPrincipals,\n } = useGetRealmPrincipals()\n\n if (isErrorEntityBundle || isErrorRealmPrincipals) {\n return null\n }\n\n if (isLoadingEntityBundle || isLoadingRealmPrincipals) {\n return <Skeleton variant=\"rounded\" width={120} height={24} />\n }\n\n const visibility = getProjectVisibilityFromACL(\n entityBundle?.benefactorAcl?.resourceAccess ?? [],\n realmPrincipals || {},\n )\n\n return <ProjectVisibilityChipUI visibility={visibility} />\n}\n"],"mappings":";;;;;;;;;;AAmBA,IAAM,IAAa;CACjB,MAAM;CACN,OAAO;AACT,GAEM,IAGF;CACF,SAAS;EACP,OAAO;EACP,OAAO;EACP,MAAM,kBAAC,GAAD,EAAkB,IAAI,EAAa,CAAA;CAC3C;CACA,cAAc;EACZ,OAAO;EACP,OAAO;EACP,MAAM,kBAAC,GAAD,EAAwB,IAAI,EAAa,CAAA;CACjD;CACA,QAAQ;EACN,OAAO;EACP,OAAO;EACP,MAAM,kBAAC,GAAD,EAAsB,IAAI,EAAa,CAAA;CAC/C;AACF;AAEA,SAAS,EAAwB,EAAE,iBAA0C;CAC3E,OACE,kBAAC,GAAD;EACE,IAAI;GACF,SAAS;GACT,SAAS;GACT,YAAY;GACZ,KAAK;GACL,cAAc;GACd,OAAO;GACP,iBAAiB,EAAkB,GAAY;GAC/C,mBAAmB;IACjB,YAAY;IACZ,aAAa;GACf;GACA,oBAAoB,EAClB,IAAI,EACN;EACF;EACA,MAAM,EAAkB,GAAY;EACpC,OACE,kBAAC,GAAD;GACE,SAAQ;GACR,IAAI;IACF,YAAY;IACZ,eAAe;GACjB;aAEC,EAAkB,GAAY;EACrB,CAAA;CAEf,CAAA;AAEL;AAEA,SAAwB,EAAsB,EAC5C,eACsC;CACtC,IAAM,EACJ,MAAM,GACN,WAAW,GACX,SAAS,MACP,EAAmB,GAAU,KAAA,GAAW,EAAE,sBAAsB,GAAK,CAAC,GACpE,EACJ,MAAM,GACN,WAAW,GACX,SAAS,MACP,EAAsB;CAe1B,OAbI,KAAuB,IAClB,OAGL,KAAyB,IACpB,kBAAC,GAAD;EAAU,SAAQ;EAAU,OAAO;EAAK,QAAQ;CAAK,CAAA,IAQvD,kBAAC,GAAD,EAAqC,YALzB,EACjB,GAAc,eAAe,kBAAkB,CAAC,GAChD,KAAmB,CAAC,CAGsB,EAAa,CAAA;AAC3D"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ResourceAccess } from '@sage-bionetworks/synapse-types';
|
|
2
|
+
export type ProjectVisibility = 'PRIVATE' | 'DISCOVERABLE' | 'PUBLIC';
|
|
3
|
+
/**
|
|
4
|
+
* Determines a project's visibility category based on its Access Control List (ACL).
|
|
5
|
+
* - **PUBLIC**: Public group has READ access AND authenticated users have both READ and DOWNLOAD access.
|
|
6
|
+
* - **DISCOVERABLE**: Public group has READ access AND authenticated users have READ access (but lack DOWNLOAD access).
|
|
7
|
+
* - **PRIVATE**: Default state; matches neither condition above.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getProjectVisibilityFromACL(resourceAccess: ResourceAccess[], realmPrincipals: {
|
|
10
|
+
publicGroup?: string;
|
|
11
|
+
authenticatedUsers?: string;
|
|
12
|
+
}): ProjectVisibility;
|
|
13
|
+
//# sourceMappingURL=getProjectVisibilityFromACL.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getProjectVisibilityFromACL.d.ts","sourceRoot":"","sources":["../../../src/components/ProjectVisibilityChip/getProjectVisibilityFromACL.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,cAAc,EAAE,MAAM,iCAAiC,CAAA;AAG7E,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,cAAc,GAAG,QAAQ,CAAA;AAErE;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,cAAc,EAAE,cAAc,EAAE,EAChC,eAAe,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE,iBAAiB,CAyBnB"}
|