diff --git a/app/client/components/BaseView.js b/app/client/components/BaseView.js index 25a02679..0ffb384f 100644 --- a/app/client/components/BaseView.js +++ b/app/client/components/BaseView.js @@ -232,6 +232,8 @@ BaseView.commonCommands = { copyLink: function() { this.copyLink().catch(reportError); }, + showRawData: function() { this.showRawData().catch(reportError); }, + filterByThisCellValue: function() { this.filterByThisCellValue(); }, duplicateRows: function() { this._duplicateRows().catch(reportError); } }; @@ -295,13 +297,26 @@ BaseView.prototype.moveEditRowToCursor = function() { return this.editRowModel; }; +// Get an anchor link for the current cell and a given view section to the clipboard. +BaseView.prototype.getAnchorLinkForSection = function(sectionId) { + const rowId = this.viewData.getRowId(this.cursor.rowIndex()) + // If there are no visible rows (happens in some widget linking situations), + // pick an arbitrary row which will hopefully be close to the top of the table. + || this.tableModel.tableData.findMatchingRowId({}) + // If there are no rows at all, return the 'new record' row ID. + // Note that this case only happens in combination with the widget linking mentioned. + // If the table is empty but the 'new record' row is selected, the `viewData.getRowId` line above works. + || 'new'; + const colRef = this.viewSection.viewFields().peek()[this.cursor.fieldIndex()].colRef(); + return {hash: {sectionId, rowId, colRef}}; +} + // Copy an anchor link for the current row to the clipboard. BaseView.prototype.copyLink = async function() { - const rowId = this.viewData.getRowId(this.cursor.rowIndex()); - const colRef = this.viewSection.viewFields().peek()[this.cursor.fieldIndex()].colRef(); const sectionId = this.viewSection.getRowId(); + const anchorUrlState = this.getAnchorLinkForSection(sectionId); try { - const link = urlState().makeUrl({ hash: { sectionId, rowId, colRef } }); + const link = urlState().makeUrl(anchorUrlState); await copyToClipboard(link); setTestState({clipboard: link}); reportSuccess('Link copied to clipboard', {key: 'clipboard'}); @@ -310,6 +325,12 @@ BaseView.prototype.copyLink = async function() { } }; +BaseView.prototype.showRawData = async function() { + const sectionId = this.schemaModel.rawViewSectionRef.peek(); + const anchorUrlState = this.getAnchorLinkForSection(sectionId); + await urlState().pushUrl({...anchorUrlState, docPage: 'data'}); +} + BaseView.prototype.filterByThisCellValue = function() { const rowId = this.viewData.getRowId(this.cursor.rowIndex()); const col = this.viewSection.viewFields().peek()[this.cursor.fieldIndex()].column(); diff --git a/app/client/components/commandList.js b/app/client/components/commandList.js index 89ae6e47..4d82500e 100644 --- a/app/client/components/commandList.js +++ b/app/client/components/commandList.js @@ -98,6 +98,11 @@ exports.groups = [{ keys: [], desc: 'Print currently selected page widget', }, + { + name: 'showRawData', + keys: [], + desc: 'Show raw data widget for table of currently selected page widget', + }, { name: 'openWidgetConfiguration', keys: [], diff --git a/app/client/ui/ViewLayoutMenu.ts b/app/client/ui/ViewLayoutMenu.ts index d5cc1ab4..3640659f 100644 --- a/app/client/ui/ViewLayoutMenu.ts +++ b/app/client/ui/ViewLayoutMenu.ts @@ -1,5 +1,6 @@ import {allCommands} from 'app/client/components/commands'; import {ViewSectionRec} from 'app/client/models/DocModel'; +import {urlState} from 'app/client/models/gristUrlState'; import {testId} from 'app/client/ui2018/cssVars'; import {menuDivider, menuItemCmd, menuItemLink} from 'app/client/ui2018/menus'; import {dom} from 'grainjs'; @@ -31,8 +32,12 @@ export function makeViewLayoutMenu(viewSection: ViewSectionRec, isReadonly: bool ]; const viewRec = viewSection.view(); + const isLight = urlState().state.get().params?.style === 'light'; return [ dom.maybe((use) => ['single'].includes(use(viewSection.parentKey)), () => contextMenu), + dom.maybe((use) => !use(viewSection.isRaw) && !isLight, + () => menuItemCmd(allCommands.showRawData, 'Show raw data', testId('show-raw-data')), + ), menuItemCmd(allCommands.printSection, 'Print widget', testId('print-section')), menuItemLink({ href: gristDoc.getCsvLink(), target: '_blank', download: ''}, 'Download as CSV', testId('download-section')), @@ -40,10 +45,12 @@ export function makeViewLayoutMenu(viewSection: ViewSectionRec, isReadonly: bool menuItemCmd(allCommands.editLayout, 'Edit Card Layout', dom.cls('disabled', isReadonly))), - menuDivider(), - menuItemCmd(allCommands.viewTabOpen, 'Widget options', testId('widget-options')), - menuItemCmd(allCommands.sortFilterTabOpen, 'Advanced Sort & Filter'), - menuItemCmd(allCommands.dataSelectionTabOpen, 'Data selection'), + dom.maybe(!isLight, () => [ + menuDivider(), + menuItemCmd(allCommands.viewTabOpen, 'Widget options', testId('widget-options')), + menuItemCmd(allCommands.sortFilterTabOpen, 'Advanced Sort & Filter'), + menuItemCmd(allCommands.dataSelectionTabOpen, 'Data selection'), + ]), menuDivider(), dom.maybe((use) => use(viewSection.parentKey) === 'custom' && use(viewSection.hasCustomOptions), () =>