(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
This commit is contained in:
Alex Hall 2022-08-02 15:01:07 +02:00
parent b6890bed4b
commit b7686fa664
3 changed files with 40 additions and 7 deletions

View File

@ -232,6 +232,8 @@ BaseView.commonCommands = {
copyLink: function() { this.copyLink().catch(reportError); }, copyLink: function() { this.copyLink().catch(reportError); },
showRawData: function() { this.showRawData().catch(reportError); },
filterByThisCellValue: function() { this.filterByThisCellValue(); }, filterByThisCellValue: function() { this.filterByThisCellValue(); },
duplicateRows: function() { this._duplicateRows().catch(reportError); } duplicateRows: function() { this._duplicateRows().catch(reportError); }
}; };
@ -295,13 +297,26 @@ BaseView.prototype.moveEditRowToCursor = function() {
return this.editRowModel; 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. // Copy an anchor link for the current row to the clipboard.
BaseView.prototype.copyLink = async function() { 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 sectionId = this.viewSection.getRowId();
const anchorUrlState = this.getAnchorLinkForSection(sectionId);
try { try {
const link = urlState().makeUrl({ hash: { sectionId, rowId, colRef } }); const link = urlState().makeUrl(anchorUrlState);
await copyToClipboard(link); await copyToClipboard(link);
setTestState({clipboard: link}); setTestState({clipboard: link});
reportSuccess('Link copied to clipboard', {key: 'clipboard'}); 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() { BaseView.prototype.filterByThisCellValue = function() {
const rowId = this.viewData.getRowId(this.cursor.rowIndex()); const rowId = this.viewData.getRowId(this.cursor.rowIndex());
const col = this.viewSection.viewFields().peek()[this.cursor.fieldIndex()].column(); const col = this.viewSection.viewFields().peek()[this.cursor.fieldIndex()].column();

View File

@ -98,6 +98,11 @@ exports.groups = [{
keys: [], keys: [],
desc: 'Print currently selected page widget', desc: 'Print currently selected page widget',
}, },
{
name: 'showRawData',
keys: [],
desc: 'Show raw data widget for table of currently selected page widget',
},
{ {
name: 'openWidgetConfiguration', name: 'openWidgetConfiguration',
keys: [], keys: [],

View File

@ -1,5 +1,6 @@
import {allCommands} from 'app/client/components/commands'; import {allCommands} from 'app/client/components/commands';
import {ViewSectionRec} from 'app/client/models/DocModel'; import {ViewSectionRec} from 'app/client/models/DocModel';
import {urlState} from 'app/client/models/gristUrlState';
import {testId} from 'app/client/ui2018/cssVars'; import {testId} from 'app/client/ui2018/cssVars';
import {menuDivider, menuItemCmd, menuItemLink} from 'app/client/ui2018/menus'; import {menuDivider, menuItemCmd, menuItemLink} from 'app/client/ui2018/menus';
import {dom} from 'grainjs'; import {dom} from 'grainjs';
@ -31,8 +32,12 @@ export function makeViewLayoutMenu(viewSection: ViewSectionRec, isReadonly: bool
]; ];
const viewRec = viewSection.view(); const viewRec = viewSection.view();
const isLight = urlState().state.get().params?.style === 'light';
return [ return [
dom.maybe((use) => ['single'].includes(use(viewSection.parentKey)), () => contextMenu), 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')), menuItemCmd(allCommands.printSection, 'Print widget', testId('print-section')),
menuItemLink({ href: gristDoc.getCsvLink(), target: '_blank', download: ''}, menuItemLink({ href: gristDoc.getCsvLink(), target: '_blank', download: ''},
'Download as CSV', testId('download-section')), 'Download as CSV', testId('download-section')),
@ -40,10 +45,12 @@ export function makeViewLayoutMenu(viewSection: ViewSectionRec, isReadonly: bool
menuItemCmd(allCommands.editLayout, 'Edit Card Layout', menuItemCmd(allCommands.editLayout, 'Edit Card Layout',
dom.cls('disabled', isReadonly))), dom.cls('disabled', isReadonly))),
menuDivider(), dom.maybe(!isLight, () => [
menuItemCmd(allCommands.viewTabOpen, 'Widget options', testId('widget-options')), menuDivider(),
menuItemCmd(allCommands.sortFilterTabOpen, 'Advanced Sort & Filter'), menuItemCmd(allCommands.viewTabOpen, 'Widget options', testId('widget-options')),
menuItemCmd(allCommands.dataSelectionTabOpen, 'Data selection'), menuItemCmd(allCommands.sortFilterTabOpen, 'Advanced Sort & Filter'),
menuItemCmd(allCommands.dataSelectionTabOpen, 'Data selection'),
]),
menuDivider(), menuDivider(),
dom.maybe((use) => use(viewSection.parentKey) === 'custom' && use(viewSection.hasCustomOptions), () => dom.maybe((use) => use(viewSection.parentKey) === 'custom' && use(viewSection.hasCustomOptions), () =>