UNPKG

synapse-react-client

Version:

[![Build Status](https://travis-ci.com/Sage-Bionetworks/Synapse-React-Client.svg?branch=main)](https://travis-ci.com/Sage-Bionetworks/Synapse-React-Client) [![npm version](https://badge.fury.io/js/synapse-react-client.svg)](https://badge.fury.io/js/synaps

758 lines 44.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DOWNLOAD_OPTIONS_CONTAINER_CLASS = exports.SORT_STATE = exports.EMPTY_HEADER = void 0; var tslib_1 = require("tslib"); var lodash_es_1 = require("lodash-es"); var React = (0, tslib_1.__importStar)(require("react")); var react_bootstrap_1 = require("react-bootstrap"); var sql_parser_1 = require("sql-parser"); var utils_1 = require("../../utils"); var getUserData_1 = require("../../utils/functions/getUserData"); var sqlFunctions_1 = require("../../utils/functions/sqlFunctions"); var synapseTypes_1 = require("../../utils/synapseTypes/"); var HasAccess_1 = (0, tslib_1.__importDefault)(require("../HasAccess")); var TotalQueryResults_1 = (0, tslib_1.__importDefault)(require("../TotalQueryResults")); var unCamelCase_1 = require("./../../utils/functions/unCamelCase"); var SynapseTableConstants_1 = require("./SynapseTableConstants"); var file_dotted_svg_1 = (0, tslib_1.__importDefault)(require("../../assets/icons/file-dotted.svg")); var SynapseTableCell_1 = require("../synapse_table_functions/SynapseTableCell"); var getUniqueEntities_1 = require("../synapse_table_functions/getUniqueEntities"); var getColumnIndiciesWithType_1 = require("../synapse_table_functions/getColumnIndiciesWithType"); var Checkbox_1 = require("../widgets/Checkbox"); var EnumFacetFilter_1 = require("../widgets/query-filter/EnumFacetFilter"); var QueryFilter_1 = require("../widgets/query-filter/QueryFilter"); var column_resizer_1 = (0, tslib_1.__importDefault)(require("column-resizer")); var ModalDownload_1 = (0, tslib_1.__importDefault)(require("../ModalDownload")); var LoadingScreen_1 = (0, tslib_1.__importDefault)(require("../LoadingScreen")); var utils_2 = require("../row_renderers/utils"); var SearchResultsNotFound_1 = (0, tslib_1.__importDefault)(require("./SearchResultsNotFound")); var SynapseConstants_1 = require("../../utils/SynapseConstants"); var AddToDownloadListV2_1 = (0, tslib_1.__importDefault)(require("../AddToDownloadListV2")); var SynapseContext_1 = require("../../utils/SynapseContext"); var getEndpoint_1 = require("../../utils/functions/getEndpoint"); var DirectDownload_1 = (0, tslib_1.__importDefault)(require("../DirectDownload")); exports.EMPTY_HEADER = { id: '', name: '', type: 'org.sagebionetworks.repo.model.FileEntity', versionNumber: -1, versionLabel: '', benefactorId: -1, createdBy: '', createdOn: '', modifiedBy: '', modifiedOn: '', }; // Hold constants for next and previous button actions var NEXT = 'NEXT'; var PREVIOUS = 'PREVIOUS'; exports.SORT_STATE = ['', 'DESC', 'ASC']; exports.DOWNLOAD_OPTIONS_CONTAINER_CLASS = 'SRC-download-options-container'; var RESIZER_OPTIONS = { resizeMode: 'overflow', partialRefresh: 'true', liveDrag: true, headerOnly: 'true', }; var SynapseTable = /** @class */ (function (_super) { (0, tslib_1.__extends)(SynapseTable, _super); function SynapseTable(props) { var _this = _super.call(this, props) || this; _this.tableElement = undefined; _this.showGroupRowData = function (selectedRow) { // magic happens - parse query, deep copy query bundle request, modify, encode, send to Synapse.org. Easy! var queryCopy = _this.props.getLastQueryRequest().query; var parsed = _this.getSqlUnderlyingDataForRow(selectedRow, queryCopy.sql); queryCopy.sql = parsed.newSql; var queryJSON = JSON.stringify(queryCopy); // encode this copy of the query (json) var encodedQuery = btoa(queryJSON); return getEndpoint_1.PRODUCTION_ENDPOINT_CONFIG.PORTAL + "#!Synapse:" + parsed.synId + "/tables/query/" + encodedQuery; }; _this.renderTable = function (headers, columnModels, facets, rows) { var _a, _b; var lastQueryRequest = (_b = (_a = _this.props).getLastQueryRequest) === null || _b === void 0 ? void 0 : _b.call(_a); // handle displaying the previous button -- if offset is zero then it // shouldn't be displayed var pastZero = lastQueryRequest.query.offset > 0; var _c = _this.props, hasMoreData = _c.hasMoreData, showAccessColumn = _c.showAccessColumn, showDownloadColumn = _c.showDownloadColumn, isRowSelectionVisible = _c.isRowSelectionVisible; var nextBtn = (React.createElement(react_bootstrap_1.Button, { variant: "secondary", className: "pill-xl", onClick: _this.handlePaginationClick(NEXT), style: { marginRight: 0, marginBottom: '20px', display: 'inline-flex', justifyContent: 'center', alignItems: 'center', }, type: "button" }, "Next")); var previousBtn = (React.createElement(react_bootstrap_1.Button, { variant: "secondary", className: "pill-xl", onClick: _this.handlePaginationClick(PREVIOUS), type: "button", style: { marginRight: !hasMoreData && pastZero ? 0 : '10px', marginBottom: '20px', display: 'inline-flex', justifyContent: 'center', alignItems: 'center', } }, "Previous")); var isShowingAccessColumn = showAccessColumn && _this.state.isEntityView; var isLoggedIn = !!_this.context.accessToken; var isShowingAddToV2DownloadListColumn = _this.state.isFileView && !_this.props.hideDownload && isLoggedIn; var isShowingDirectDownloadColumn = _this.state.isFileView && showDownloadColumn && isLoggedIn; /* min height ensure if no rows are selected that a dropdown menu is still accessible */ var tableEntityId = lastQueryRequest === null || lastQueryRequest === void 0 ? void 0 : lastQueryRequest.entityId; return (React.createElement("div", { style: { minHeight: '400px' }, className: "SRC-overflowAuto", "data-testid": "SynapseTable" }, React.createElement("table", { ref: function (node) { return (_this.tableElement = node); }, className: "table table-striped table-condensed" }, React.createElement("thead", { className: "SRC_bordered" }, React.createElement("tr", null, _this.createTableHeader(headers, columnModels, facets, isShowingAccessColumn, isShowingDirectDownloadColumn, isShowingAddToV2DownloadListColumn, isRowSelectionVisible, lastQueryRequest))), React.createElement("tbody", null, _this.createTableRows(rows, headers, isShowingAccessColumn, isShowingDirectDownloadColumn, isShowingAddToV2DownloadListColumn, isRowSelectionVisible, tableEntityId))), React.createElement("div", { className: "bootstrap-4-backport", style: { textAlign: 'right' } }, pastZero && previousBtn, hasMoreData && nextBtn))); }; /** * Handle a click on next or previous * * @memberof SynapseTable */ _this.handlePaginationClick = function (eventType) { return function (_event) { var _a, _b; var queryRequest = _this.props.getLastQueryRequest(); var currentOffset = queryRequest.query.offset; // if its a "previous" click subtract from the offset // otherwise its next and we paginate forward if (eventType === PREVIOUS) { currentOffset -= (_a = queryRequest.query.limit) !== null && _a !== void 0 ? _a : SynapseConstants_1.DEFAULT_PAGE_SIZE; } if (eventType === NEXT) { currentOffset += (_b = queryRequest.query.limit) !== null && _b !== void 0 ? _b : SynapseConstants_1.DEFAULT_PAGE_SIZE; } queryRequest.query.offset = currentOffset; _this.props.executeQueryRequest(queryRequest); }; }; /** * Handle a column having been selected * * @memberof SynapseTable */ _this.handleColumnSortPress = function (dict) { return function (_) { // by using Synthetic event we can use the handler on both key press and mouse click var columnIconSortState = (0, lodash_es_1.cloneDeep)(_this.state.columnIconSortState); if (columnIconSortState.length === 0) { columnIconSortState = Array(_this.getLengthOfPropsData()).fill(0); } // get currently sorted items and remove/insert/update this selection var sortedColumnSelection = (0, lodash_es_1.cloneDeep)(_this.state.sortedColumnSelection); var index = _this.findSelectionIndex(sortedColumnSelection, dict.name); // if its present then remove it if (index !== -1) { sortedColumnSelection.splice(index, 1); } columnIconSortState[dict.index] = (columnIconSortState[dict.index] + 1) % SynapseTableConstants_1.ICON_STATE.length; if (columnIconSortState[dict.index] > 0) { sortedColumnSelection.unshift({ column: dict.name, direction: exports.SORT_STATE[columnIconSortState[dict.index]], }); } var queryRequest = _this.props.getLastQueryRequest(); queryRequest.query.sort = sortedColumnSelection; queryRequest.query.offset = 0; _this.props.executeQueryRequest(queryRequest); _this.setState({ columnIconSortState: columnIconSortState, sortedColumnSelection: sortedColumnSelection, }); }; }; /** * Handles the toggle of a column select, this will cause the table to * either show the column or hide depending on the prior state of the column * * @memberof SynapseTable */ _this.toggleColumnSelection = function (columnName) { var isColumnSelected = (0, lodash_es_1.cloneDeep)(_this.props.isColumnSelected); if (isColumnSelected.includes(columnName)) { isColumnSelected = isColumnSelected.filter(function (el) { return el !== columnName; }); } else { isColumnSelected.push(columnName); } _this.props.updateParentState({ isColumnSelected: isColumnSelected }); }; _this.applyChangesFromQueryFilter = function (facets) { var queryRequest = _this.props.getLastQueryRequest(); queryRequest.query.selectedFacets = facets; queryRequest.query.offset = 0; _this.props.executeQueryRequest(queryRequest); }; _this.componentDidMount = _this.componentDidMount.bind(_this); _this.componentWillUnmount = _this.componentWillUnmount.bind(_this); _this.componentDidUpdate = _this.componentDidUpdate.bind(_this); _this.shouldComponentUpdate = _this.shouldComponentUpdate.bind(_this); _this.handleColumnSortPress = _this.handleColumnSortPress.bind(_this); _this.handlePaginationClick = _this.handlePaginationClick.bind(_this); _this.findSelectionIndex = _this.findSelectionIndex.bind(_this); _this.toggleColumnSelection = _this.toggleColumnSelection.bind(_this); _this.advancedSearch = _this.advancedSearch.bind(_this); _this.getLengthOfPropsData = _this.getLengthOfPropsData.bind(_this); _this.configureFacetDropdown = _this.configureFacetDropdown.bind(_this); _this.enableResize = _this.enableResize.bind(_this); _this.disableResize = _this.disableResize.bind(_this); // store the offset and sorted selection that is currently held _this.state = { /* columnIconSortState tells what icon to display for a table header. There are three states for a particular header- 0 - show descending icon but *deselected* 1 - show descending icon selected 2 - show ascending icon selected */ columnIconSortState: [], isExportTableDownloadOpen: false, isExpanded: false, isColumnSelectionOpen: false, isEntityView: false, isFileView: false, // sortedColumnSelection contains the columns which are // selected currently and their sort status as eithet // off, desc, or asc. sortedColumnSelection: [], mapEntityIdToHeader: {}, mapUserIdToHeader: {}, isFetchingEntityHeaders: false, isFetchingEntityVersion: false, }; _this.getEntityHeadersInData = _this.getEntityHeadersInData.bind(_this); return _this; } SynapseTable.prototype.componentWillUnmount = function () { this.disableResize(); }; SynapseTable.prototype.componentDidMount = function () { this.getEntityHeadersInData(true); this.enableResize(); }; SynapseTable.prototype.shouldComponentUpdate = function (nextProps, nextState, nextContext) { this.disableResize(); return _super.prototype.shouldComponentUpdate ? _super.prototype.shouldComponentUpdate.call(this, nextProps, nextState, nextContext) : true; }; SynapseTable.prototype.componentDidUpdate = function (prevProps) { this.getEntityHeadersInData(false); this.getTableConcreteType(prevProps); this.enableResize(); }; SynapseTable.prototype.getTableConcreteType = function (prevProps) { var _a; return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var token, data, currentTableId, previousTableId, entityData, isEntityView, isFileView; return (0, tslib_1.__generator)(this, function (_b) { switch (_b.label) { case 0: token = this.context.accessToken; data = this.props.data; if (!data || this.state.isFetchingEntityVersion) { return [2 /*return*/]; } currentTableId = data === null || data === void 0 ? void 0 : data.queryResult.queryResults.tableId; previousTableId = (_a = prevProps.data) === null || _a === void 0 ? void 0 : _a.queryResult.queryResults.tableId; if (!(currentTableId && previousTableId !== currentTableId)) return [3 /*break*/, 2]; this.setState({ isFetchingEntityVersion: true, }); return [4 /*yield*/, utils_1.SynapseClient.getEntity(token, currentTableId)]; case 1: entityData = _b.sent(); isEntityView = entityData.concreteType.includes('EntityView'); isFileView = isEntityView ? (entityData.viewTypeMask & 1) != 0 : false; this.setState({ isEntityView: isEntityView, isFileView: isFileView, isFetchingEntityVersion: false, }); _b.label = 2; case 2: return [2 /*return*/]; } }); }); }; SynapseTable.prototype.enableResize = function () { if (!this.resizer) { if (this.tableElement) { this.resizer = new column_resizer_1.default(this.tableElement, RESIZER_OPTIONS); } } else { this.resizer.reset(RESIZER_OPTIONS); } }; SynapseTable.prototype.disableResize = function () { if (this.resizer) { this.resizer.reset({ disable: true }); } }; SynapseTable.prototype.getEntityHeadersInData = function (forceRefresh) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var data, mapEntityIdToHeader, mapUserIdToHeader, entityIdColumnIndicies, userIdColumnIndicies, distinctEntityIds, queryResult, queryResults, rows, distinctUserIds, referenceList, data_1, results, err_1, userPorfileIds, ids, data_2, err_2, data_3, err_3; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: data = this.props.data; if (!data) { return [2 /*return*/]; } else if (this.state.isFetchingEntityHeaders && !forceRefresh) { return [2 /*return*/]; } mapEntityIdToHeader = (0, lodash_es_1.cloneDeep)(this.state.mapEntityIdToHeader); mapUserIdToHeader = (0, lodash_es_1.cloneDeep)(this.state.mapUserIdToHeader); entityIdColumnIndicies = (0, getColumnIndiciesWithType_1.getColumnIndiciesWithType)(this.props.data, synapseTypes_1.ColumnType.ENTITYID); userIdColumnIndicies = (0, getColumnIndiciesWithType_1.getColumnIndiciesWithType)(this.props.data, synapseTypes_1.ColumnType.USERID); distinctEntityIds = (0, getUniqueEntities_1.getUniqueEntities)(data, mapEntityIdToHeader, entityIdColumnIndicies); // also include row entity ids if this is a view (it's possible that the ID column was not selected) if (this.state.isEntityView) { queryResult = data.queryResult; queryResults = queryResult.queryResults; rows = queryResults.rows; rows.forEach(function (row) { var rowSynapseId = "syn" + row.rowId; distinctEntityIds.add(rowSynapseId); }); } distinctUserIds = (0, getUniqueEntities_1.getUniqueEntities)(data, mapUserIdToHeader, userIdColumnIndicies); if (distinctEntityIds.size === 0 && distinctUserIds.size === 0) { return [2 /*return*/]; } this.setState({ isFetchingEntityHeaders: true, }); if (!(distinctEntityIds.size > 0)) return [3 /*break*/, 4]; referenceList = Array.from(distinctEntityIds).map(function (id) { return { targetId: id }; }); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); // initialize mapEntityIdToHeader referenceList.forEach(function (el) { mapEntityIdToHeader[el.targetId] = exports.EMPTY_HEADER; }); return [4 /*yield*/, utils_1.SynapseClient.getEntityHeaders(referenceList, this.context.accessToken)]; case 2: data_1 = _a.sent(); results = data_1.results; results.forEach(function (el) { mapEntityIdToHeader[el.id] = el; }); return [3 /*break*/, 4]; case 3: err_1 = _a.sent(); console.error('Error on retrieving entity header list , ', err_1); return [3 /*break*/, 4]; case 4: userPorfileIds = []; if (!(distinctUserIds.size > 0)) return [3 /*break*/, 8]; ids = Array.from(distinctUserIds); _a.label = 5; case 5: _a.trys.push([5, 7, , 8]); return [4 /*yield*/, utils_1.SynapseClient.getGroupHeadersBatch(ids, this.context.accessToken)]; case 6: data_2 = _a.sent(); data_2.children.forEach(function (el) { if (el.isIndividual) { userPorfileIds.push(el.ownerId); } else { mapUserIdToHeader[el.ownerId] = el; } }); return [3 /*break*/, 8]; case 7: err_2 = _a.sent(); console.error('Error on getGroupHeaders batch: ', err_2); return [3 /*break*/, 8]; case 8: if (!(userPorfileIds.length > 0)) return [3 /*break*/, 12]; _a.label = 9; case 9: _a.trys.push([9, 11, , 12]); return [4 /*yield*/, (0, getUserData_1.getUserProfileWithProfilePicAttached)(userPorfileIds)]; case 10: data_3 = _a.sent(); data_3.list.forEach(function (el) { mapUserIdToHeader[el.ownerId] = el; }); return [3 /*break*/, 12]; case 11: err_3 = _a.sent(); console.error('Error on getUserProfile : ', err_3); return [3 /*break*/, 12]; case 12: this.setState({ mapEntityIdToHeader: mapEntityIdToHeader, mapUserIdToHeader: mapUserIdToHeader, isFetchingEntityHeaders: false, }); return [2 /*return*/]; } }); }); }; /** * Display the view */ SynapseTable.prototype.render = function () { var _this = this; if (this.props.isLoadingNewData) { return LoadingScreen_1.default; } else if (!this.props.data) { return React.createElement(React.Fragment, null); } // unpack all the data var _a = this.props, data = _a.data, _b = _a.isLoading, isLoading = _b === void 0 ? true : _b, unitDescription = _a.unitDescription, showBarChart = _a.showBarChart, topLevelControlsState = _a.topLevelControlsState; var queryResult = data.queryResult, _c = data.columnModels, columnModels = _c === void 0 ? [] : _c; var queryResults = queryResult.queryResults; var rows = queryResults.rows; var headers = queryResults.headers; var _d = data.facets, facets = _d === void 0 ? [] : _d; var _e = this.state, isExpanded = _e.isExpanded, isExportTableDownloadOpen = _e.isExportTableDownloadOpen; var queryRequest = this.props.getLastQueryRequest(); var showFacetFilter = topLevelControlsState.showFacetFilter; var className = ''; if (showBarChart) { className = 'SRC-marginBottomTop'; } var hasResults = data.queryResult.queryResults.rows.length > 0; // Show the No Results UI if the current page has no rows, and this is the first page of data (offset === 0). if (!hasResults && queryRequest.query.offset === 0) { if (queryRequest.query.additionalFilters) { return React.createElement(SearchResultsNotFound_1.default, null); } else { return (React.createElement("div", { className: "text-center SRCBorderedPanel SRCBorderedPanel--padded2x" }, React.createElement("img", { src: file_dotted_svg_1.default, alt: "no data" }), React.createElement("div", { style: { marginTop: '20px', fontStyle: 'italic' } }, "This table is currently empty"))); } } var table = (React.createElement("div", null, this.renderTable(headers, columnModels, facets, rows))); var content = (React.createElement(React.Fragment, null, React.createElement("div", { className: className }, isExportTableDownloadOpen && (React.createElement(ModalDownload_1.default, { onClose: function () { _this.setState({ isExportTableDownloadOpen: false, }); }, queryBundleRequest: queryRequest })), !showFacetFilter && unitDescription && !(0, sqlFunctions_1.isGroupByInSql)(queryRequest.query.sql) && (React.createElement("div", { className: "SRC-centerContent text-left", style: { minHeight: '20px' } }, React.createElement(TotalQueryResults_1.default, { isLoading: isLoading, style: { fontSize: 15 }, unitDescription: unitDescription, lastQueryRequest: queryRequest, frontText: 'Showing', applyChanges: function (newFacets) { return _this.applyChangesFromQueryFilter(newFacets); } }))), React.createElement("div", null, table)))); return (React.createElement(React.Fragment, null, isExpanded && (React.createElement(react_bootstrap_1.Modal, { animation: false, show: true, // @ts-ignore onHide: function () { return _this.setState({ isExpanded: false }); }, dialogClassName: 'modal-90w' }, React.createElement(react_bootstrap_1.Modal.Header // @ts-ignore , { // @ts-ignore onHide: function () { return _this.setState({ isExpanded: false }); }, closeButton: true }), React.createElement(react_bootstrap_1.Modal.Body, null, content))), !isExpanded && content)); }; /** * Return the select column indexes for columns that use the aggregate count function. * If sql does not have a GROUP BY, this returns an empty array. * @param originalSql */ SynapseTable.prototype.getCountFunctionColumnIndexes = function (originalSql) { var indexes = []; if ((0, sqlFunctions_1.isGroupByInSql)(originalSql)) { var tokens = sql_parser_1.lexer.tokenize(originalSql); var selectIndex = tokens.findIndex(function (el) { return el[0] === 'SELECT'; }); var fromIndex = tokens.findIndex(function (el) { return el[0] === 'FROM'; }); var columnIndex = 0; for (var index = selectIndex + 1; index < fromIndex - selectIndex - 1; index += 1) { var token = tokens[index]; if (token[0] === 'FUNCTION' && token[1].toLowerCase() === 'count') { // found a count column! indexes.push(columnIndex); } else if (token[0] === 'SEPARATOR') { // next column columnIndex += 1; } } } return indexes; }; SynapseTable.prototype.getSqlUnderlyingDataForRow = function (selectedRow, originalSql) { var tokens = sql_parser_1.lexer.tokenize(originalSql); var selectIndex = tokens.findIndex(function (el) { return el[0] === 'SELECT'; }); var fromIndex = tokens.findIndex(function (el) { return el[0] === 'FROM'; }); // gather all of the column names literals between select and from (and their indices) var columnReferences = []; var columnIndex = 0; var foundFunctionForColumn = false; for (var index = selectIndex + 1; index < fromIndex - selectIndex - 1; index += 1) { var token = tokens[index]; // parsing error. concat function is reported as a LITERAL instead of a function if (token[0] === 'FUNCTION' || token[1].toLocaleLowerCase() === 'concat') { foundFunctionForColumn = true; } else if (token[0] === 'LITERAL' && !foundFunctionForColumn) { // found a column columnReferences.push({ index: columnIndex, name: token[1] }); } else if (token[0] === 'SEPARATOR') { // next column columnIndex += 1; // reset "found function" foundFunctionForColumn = false; } } // remove all tokens after (and including) group tokens = tokens.slice(0, tokens.findIndex(function (el) { return el[0] === 'GROUP'; })); // replace all columns with * tokens.splice(selectIndex + 1, fromIndex - selectIndex - 1, [ 'STAR', '*', '1', ]); // add new items to where clause, but only if the column name corresponds to a real column in the table/view! // use row.values if (this.props.data === undefined) { return { synId: '', newSql: '' }; } var whereIndex = tokens.findIndex(function (el) { return el[0] === 'WHERE'; }); if (whereIndex === -1) { // does not contain a where clause tokens.push(['WHERE', 'WHERE', '1']); } else { // alreay contains a where clause, add the first AND tokens.push(['CONDITIONAL', 'AND', '1']); } // look for headers in column models, if they match then add a where clause columnReferences.forEach(function (value, index) { var rowValue = selectedRow.values[value.index]; // PORTALS-712: support null values if (rowValue) { tokens.push(['LITERAL', value.name, '1'], ['OPERATOR', '=', '1'], ['STRING', rowValue, '1'], ['CONDITIONAL', 'AND', '1']); } else { tokens.push(['LITERAL', value.name, '1'], ['OPERATOR', 'IS', '1'], ['BOOLEAN', 'null', '1'], ['CONDITIONAL', 'AND', '1']); } }); // remove the last AND tokens.pop(); // remove backtick from output sql (for table name): `syn1234` becomes syn1234 var synId = tokens[tokens.findIndex(function (el) { return el[0] === 'FROM'; }) + 1][1]; tokens.push(['EOF', '', '1']); return { synId: synId, newSql: (0, sqlFunctions_1.formatSQLFromParser)(tokens) }; }; SynapseTable.prototype.createTableRows = function (rows, headers, isShowingAccessColumn, isShowingDownloadColumn, isShowingAddToV2DownloadListColumn, isRowSelectionVisible, tableEntityId) { var _this = this; var rowsFormatted = []; var _a = this.props, data = _a.data, isColumnSelected = _a.isColumnSelected, selectedRowIndices = _a.selectedRowIndices, updateParentState = _a.updateParentState, _b = _a.columnLinks, columnLinks = _b === void 0 ? [] : _b; var _c = data, _d = _c.selectColumns, selectColumns = _d === void 0 ? [] : _d, _e = _c.columnModels, columnModels = _e === void 0 ? [] : _e; var _f = this.state, mapEntityIdToHeader = _f.mapEntityIdToHeader, mapUserIdToHeader = _f.mapUserIdToHeader; // find column indices that are COUNT type var countColumnIndexes = this.getCountFunctionColumnIndexes(this.props.getLastQueryRequest().query.sql); rows.forEach(function (row, rowIndex) { var _a, _b; var entityVersionNumber = (_a = row.versionNumber) === null || _a === void 0 ? void 0 : _a.toString(); var rowSynapseId = "syn" + row.rowId; var rowContent = row.values.map(function (columnValue, colIndex) { var columnName = headers[colIndex].name; var isColumnActive = isColumnSelected.includes(columnName); var columnLinkConfig = columnLinks.find(function (el) { return el.matchColumnName === columnName; }); var index = _this.findSelectionIndex(_this.state.sortedColumnSelection, columnName); var isCountColumn = countColumnIndexes.includes(colIndex); var isBold = index === -1 ? '' : 'SRC-boldText'; if (isColumnActive) { return (React.createElement("td", { className: "SRC_noBorderTop SRC-synapseTableTd", key: "(" + rowIndex + columnValue + colIndex + ")" }, isCountColumn && (React.createElement("a", { href: _this.showGroupRowData(row), target: "_blank", rel: "noopener noreferrer" }, React.createElement("p", { className: isBold }, columnValue))), !isCountColumn && (React.createElement(SynapseTableCell_1.SynapseTableCell, { columnType: headers[colIndex].columnType, columnValue: columnValue, isBold: isBold, mapEntityIdToHeader: mapEntityIdToHeader, mapUserIdToHeader: mapUserIdToHeader, rowIndex: rowIndex, columnLinkConfig: columnLinkConfig, columnName: columnName, tableEntityId: tableEntityId, rowData: row.values, selectColumns: selectColumns, columnModels: columnModels })))); } return React.createElement("td", { className: "SRC-hidden", key: "(" + rowIndex + "," + colIndex + ")" }); }); // also push the access column value if we are showing user access for individual items (still shown if not logged in) if (isShowingAccessColumn) { rowContent.unshift(React.createElement("td", { key: rowSynapseId, className: "SRC_noBorderTop" }, React.createElement(HasAccess_1.default, { key: rowSynapseId, entityId: rowSynapseId, entityVersionNumber: entityVersionNumber }))); } var isFileEntity = ((_b = mapEntityIdToHeader[rowSynapseId]) === null || _b === void 0 ? void 0 : _b.type) == 'org.sagebionetworks.repo.model.FileEntity'; if (isShowingDownloadColumn) { // SWC-5790: If this is a FileEntity, the download icon should just go to entity page rowContent.unshift(React.createElement("td", { className: "SRC_noBorderTop direct-download" }, isFileEntity && (React.createElement(DirectDownload_1.default, { key: 'direct-download-' + rowSynapseId, associatedObjectId: rowSynapseId, entityVersionNumber: entityVersionNumber })))); } if (isShowingAddToV2DownloadListColumn) { rowContent.unshift(React.createElement("td", { className: "SRC_noBorderTop add-to-download-list-v2" }, isFileEntity && (React.createElement(AddToDownloadListV2_1.default, { key: 'add-to-download-list-v2-' + rowSynapseId, entityId: rowSynapseId, entityVersionNumber: parseInt(entityVersionNumber) })))); } if (isRowSelectionVisible && selectedRowIndices) { rowContent.unshift(React.createElement("td", { key: "(" + rowIndex + ",rowSelectColumn)", className: "SRC_noBorderTop" }, React.createElement(Checkbox_1.Checkbox, { label: "", checked: selectedRowIndices.includes(rowIndex), onChange: function (checked) { var cloneSelectedRowIndices = (0, tslib_1.__spreadArray)([], selectedRowIndices, true); if (checked) { cloneSelectedRowIndices.push(rowIndex); } else { var index = cloneSelectedRowIndices.indexOf(rowIndex); if (index > -1) { cloneSelectedRowIndices.splice(index, 1); } } // update parent state on change updateParentState({ selectedRowIndices: cloneSelectedRowIndices, }); } }))); } var rowFormatted = React.createElement("tr", { key: row.rowId }, rowContent); rowsFormatted.push(rowFormatted); }); return rowsFormatted; }; SynapseTable.prototype.isSortableColumn = function (column) { switch (column) { case synapseTypes_1.ColumnType.USERID: case synapseTypes_1.ColumnType.ENTITYID: case synapseTypes_1.ColumnType.FILEHANDLEID: return false; default: return true; } }; SynapseTable.prototype.createTableHeader = function (headers, columnModels, facets, isShowingAccessColumn, isShowingDownloadColumn, isShowingAddToV2DownloadListColumn, isRowSelectionVisible, lastQueryRequest) { var _this = this; var _a = this.state, sortedColumnSelection = _a.sortedColumnSelection, columnIconSortState = _a.columnIconSortState; var _b = this.props, _c = _b.facetAliases, facetAliases = _c === void 0 ? {} : _c, isColumnSelected = _b.isColumnSelected, lockedFacet = _b.lockedFacet; var tableColumnHeaderElements = headers.map(function (column, index) { var _a; var isHeaderSelected = isColumnSelected.includes(column.name); if (isHeaderSelected) { // for background color var isSelected = _this.findSelectionIndex(sortedColumnSelection, column.name) !== -1; // for icon state var columnIndex = columnIconSortState[index] === undefined ? 0 : columnIconSortState[index]; // we have to figure out if the current column is a facet selection var facetIndex = facets.findIndex(function (facetColumnResult) { return facetColumnResult.columnName === column.name; }); // the header must be included in the facets and it has to be enumerable for current rendering capabilities var isFacetSelection = facetIndex !== -1 && facets[facetIndex].facetType === 'enumeration'; var facet = facets[facetIndex]; var isSelectedSpanClass = isSelected ? 'SRC-primary-background-color SRC-anchor-light' : ''; var isSelectedIconClass = isSelected ? 'SRC-selected-table-icon tool-icon' : 'SRC-primary-text-color tool-icon'; var sortSpanBackgoundClass = "SRC-tableHead SRC-hand-cursor SRC-sortPadding SRC-primary-background-color-hover " + isSelectedSpanClass; var displayColumnName = (0, unCamelCase_1.unCamelCase)(column.name, facetAliases); var columnModel = columnModels.find(function (el) { return el.name === column.name; }); var isLockedFacetColumn = column.name.toLowerCase() === ((_a = lockedFacet === null || lockedFacet === void 0 ? void 0 : lockedFacet.facet) === null || _a === void 0 ? void 0 : _a.toLowerCase()); // used in details page to disable filter the column return (React.createElement("th", { key: column.name }, React.createElement("div", { className: "SRC-split" }, React.createElement("span", { style: { whiteSpace: 'nowrap' } }, displayColumnName), React.createElement("div", { className: "SRC-centerContent" }, isFacetSelection && !isLockedFacetColumn && _this.configureFacetDropdown(facet, columnModel, lastQueryRequest, facetAliases), _this.isSortableColumn(column.columnType) && (React.createElement("span", { tabIndex: 0, className: sortSpanBackgoundClass, onKeyPress: _this.handleColumnSortPress({ index: index, name: column.name, }), onClick: _this.handleColumnSortPress({ index: index, name: column.name, }) }, React.createElement(utils_2.Icon, { type: SynapseTableConstants_1.ICON_STATE[columnIndex], cssClass: isSelectedIconClass }))))))); } else { return React.createElement("th", { className: "SRC-hidden", key: column.name }); } }); // also push the access column if we are showing user access for individual items (must be logged in) if (isShowingAccessColumn) { tableColumnHeaderElements.unshift(React.createElement("th", { key: "accessColumn" }, React.createElement("div", { className: "SRC-centerContent" }, React.createElement("span", { style: { whiteSpace: 'nowrap' } }, "Access")))); } // add direct download column if logged in if (isShowingDownloadColumn) { tableColumnHeaderElements.unshift(React.createElement("th", { key: "downloadColumn" }, React.createElement("div", { className: "SRC-centerContent" }, "\u00A0"))); } if (isShowingAddToV2DownloadListColumn) { tableColumnHeaderElements.unshift(React.createElement("th", { key: "addToV2DownloadListColumn" }, React.createElement("div", { className: "SRC-centerContent" }, "\u00A0"))); } if (isRowSelectionVisible) { tableColumnHeaderElements.unshift(React.createElement("th", { key: "rowSelectionColumn" }, React.createElement("div", { className: "SRC-centerContent" }))); } return tableColumnHeaderElements; }; /** * Utility to search through array of objects and find object with key "column" * equal to input parameter "name" * * @param {*} sortedColumnSelection * @param {*} name * @returns -1 if not present, otherwise the index of the object * @memberof SynapseTable */ SynapseTable.prototype.findSelectionIndex = function (sortedColumnSelection, name) { if (sortedColumnSelection.length !== 0) { // find if the current selection exists already and remove it return sortedColumnSelection.findIndex(function (el) { return el.column === name; }); } return -1; }; // Direct user to corresponding query on synapse SynapseTable.prototype.advancedSearch = function (event) { event && event.preventDefault(); var lastQueryRequest = this.props.getLastQueryRequest(); var query = lastQueryRequest.query; // base 64 encode the json of the query and go to url with the encoded object var encodedQuery = btoa(JSON.stringify(query)); var synTable = lastQueryRequest.entityId; window.open(getEndpoint_1.PRODUCTION_ENDPOINT_CONFIG.PORTAL + "#!Synapse:" + synTable + "/tables/query/" + encodedQuery, '_blank'); }; SynapseTable.prototype.getLengthOfPropsData = function () { var data = this.props.data; return data.queryResult.queryResults.headers.length; }; /** * Show the dropdown menu for a column that has been faceted * * @param {number} index this is column index of the query table data * @param {string} columnName this is the name of the column * @param {FacetColumnResult[]} facetColumnResults * @param {number} facetIndex * @returns * @memberof SynapseTable */ SynapseTable.prototype.configureFacetDropdown = function (facetColumnResult, columnModel, lastQueryRequest, facetAliases) { var _this = this; return (React.createElement(EnumFacetFilter_1.EnumFacetFilter, { containerAs: "Dropdown", facetValues: facetColumnResult.facetValues, columnModel: columnModel, facetAliases: facetAliases, onChange: function (facetNamesMap) { (0, QueryFilter_1.applyMultipleChangesToValuesColumn)(lastQueryRequest, facetColumnResult, _this.applyChangesFromQueryFilter, facetNamesMap); }, onClear: function () { (0, QueryFilter_1.applyChangesToValuesColumn)(lastQueryRequest, facetColumnResult, _this.applyChangesFromQueryFilter); } })); }; SynapseTable.contextType = SynapseContext_1.SynapseContext; return SynapseTable; }(React.Component)); exports.default = SynapseTable; //# sourceMappingURL=SynapseTable.js.map