From b7686fa664c6b450e129b16c79cb993a9abfd147 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Tue, 2 Aug 2022 15:01:07 +0200 Subject: [PATCH] (core) Add 'Show raw data' widget menu option Summary: Adds a new option to the top of the three dot widget menu which navigates to the raw data widget at the current cell, equivalent to clicking an anchor link. Clicking the back button returns to the previous view. Clicking the close button shows the list of raw data tables instead, which isn't great, but the same is true when clicking an anchor link. Test Plan: Added a test to `nbrowser/ChartView1.ts` because charts are the main thing we want this for. Reviewers: jarek Reviewed By: jarek Subscribers: jarek Differential Revision: https://phab.getgrist.com/D3539 --- app/client/components/BaseView.js | 27 ++++++++++++++++++++++++--- app/client/components/commandList.js | 5 +++++ app/client/ui/ViewLayoutMenu.ts | 15 +++++++++++---- 3 files changed, 40 insertions(+), 7 deletions(-) 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), () =>