mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Show summary tables on Raw Data page
Summary: Summary tables now have their own raw viewsection, and are shown under Raw Data Tables on the Raw Data page. Test Plan: Browser and Python tests. Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D3495
This commit is contained in:
@@ -20,10 +20,13 @@ export class DataTables extends Disposable {
|
||||
private _view: Observable<string | null>;
|
||||
constructor(private _gristDoc: GristDoc) {
|
||||
super();
|
||||
// Remove tables that we don't have access to. ACL will remove tableId from those tables.
|
||||
this._tables = Computed.create(this, use =>
|
||||
use(_gristDoc.docModel.rawTables.getObservable())
|
||||
.filter(t => Boolean(use(t.tableId))));
|
||||
this._tables = Computed.create(this, use => {
|
||||
const dataTables = use(_gristDoc.docModel.rawDataTables.getObservable());
|
||||
const summaryTables = use(_gristDoc.docModel.rawSummaryTables.getObservable());
|
||||
// Remove tables that we don't have access to. ACL will remove tableId from those tables.
|
||||
return [...dataTables, ...summaryTables].filter(t => Boolean(use(t.tableId)));
|
||||
});
|
||||
|
||||
// Get the user id, to remember selected layout on the next visit.
|
||||
const userId = this._gristDoc.app.topAppModel.appObs.get()?.currentUser?.id ?? 0;
|
||||
this._view = this.autoDispose(localStorageObs(`u=${userId}:raw:viewType`, "list"));
|
||||
@@ -35,7 +38,7 @@ export class DataTables extends Disposable {
|
||||
/*************** List section **********/
|
||||
testId('list'),
|
||||
cssBetween(
|
||||
docListHeader('Raw data tables'),
|
||||
docListHeader('Raw Data Tables'),
|
||||
cssSwitch(
|
||||
buttonSelect<any>(
|
||||
this._view,
|
||||
@@ -54,32 +57,13 @@ export class DataTables extends Disposable {
|
||||
cssItem(
|
||||
testId('table'),
|
||||
cssLeft(
|
||||
dom.domComputed(tableRec.tableId, (tableId) =>
|
||||
cssGreenIcon(
|
||||
'TypeTable',
|
||||
testId(`table-id-${tableId}`)
|
||||
)
|
||||
),
|
||||
dom.domComputed((use) => cssGreenIcon(
|
||||
use(tableRec.summarySourceTable) !== 0 ? 'PivotLight' : 'TypeTable',
|
||||
testId(`table-id-${use(tableRec.tableId)}`)
|
||||
)),
|
||||
),
|
||||
cssMiddle(
|
||||
css60(
|
||||
testId('table-title'),
|
||||
dom.domComputed(fromKo(tableRec.rawViewSectionRef), vsRef => {
|
||||
if (!vsRef) {
|
||||
// Some very old documents might not have rawViewSection.
|
||||
return dom('span', dom.text(tableRec.tableNameDef));
|
||||
} else {
|
||||
return dom('div', // to disable flex grow in the widget
|
||||
dom.domComputed(fromKo(tableRec.rawViewSection), vs =>
|
||||
dom.update(
|
||||
buildTableName(vs, testId('widget-title')),
|
||||
dom.on('click', (ev) => { ev.stopPropagation(); ev.preventDefault(); }),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}),
|
||||
),
|
||||
css60(this._tableTitle(tableRec), testId('table-title')),
|
||||
css40(
|
||||
cssIdHoverWrapper(
|
||||
cssUpperCase("Table id: "),
|
||||
@@ -122,6 +106,30 @@ export class DataTables extends Disposable {
|
||||
);
|
||||
}
|
||||
|
||||
private _tableTitle(table: TableRec) {
|
||||
return dom.domComputed((use) => {
|
||||
const rawViewSectionRef = use(fromKo(table.rawViewSectionRef));
|
||||
const isSummaryTable = use(table.summarySourceTable) !== 0;
|
||||
if (!rawViewSectionRef || isSummaryTable) {
|
||||
// Some very old documents might not have a rawViewSection, and raw summary
|
||||
// tables can't currently be renamed.
|
||||
const tableName = [
|
||||
use(table.tableNameDef), isSummaryTable ? use(table.groupDesc) : ''
|
||||
].filter(p => Boolean(p?.trim())).join(' ');
|
||||
return dom('span', tableName);
|
||||
} else {
|
||||
return dom('div', // to disable flex grow in the widget
|
||||
dom.domComputed(fromKo(table.rawViewSection), vs =>
|
||||
dom.update(
|
||||
buildTableName(vs, testId('widget-title')),
|
||||
dom.on('click', (ev) => { ev.stopPropagation(); ev.preventDefault(); }),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _menuItems(table: TableRec) {
|
||||
const {isReadonly, docModel} = this._gristDoc;
|
||||
return [
|
||||
@@ -130,8 +138,8 @@ export class DataTables extends Disposable {
|
||||
'Remove',
|
||||
testId('menu-remove'),
|
||||
dom.cls('disabled', use => use(isReadonly) || (
|
||||
// Can't delete last user table, unless it is a hidden table.
|
||||
use(docModel.allTables.getObservable()).length <= 1 && !use(table.isHidden)
|
||||
// Can't delete last visible table, unless it is a hidden table.
|
||||
use(docModel.visibleTables.getObservable()).length <= 1 && !use(table.isHidden)
|
||||
))
|
||||
),
|
||||
dom.maybe(isReadonly, () => menuText('You do not have edit access to this document')),
|
||||
@@ -141,9 +149,9 @@ export class DataTables extends Disposable {
|
||||
private _removeTable(t: TableRec) {
|
||||
const {docModel} = this._gristDoc;
|
||||
function doRemove() {
|
||||
return docModel.docData.sendAction(['RemoveTable', t.tableId.peek()]);
|
||||
return docModel.docData.sendAction(['RemoveTable', t.tableId()]);
|
||||
}
|
||||
confirmModal(`Delete ${t.tableId()} data, and remove it from all pages?`, 'Delete', doRemove);
|
||||
confirmModal(`Delete ${t.formattedTableName()} data, and remove it from all pages?`, 'Delete', doRemove);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ export class GristDoc extends DisposableWithEvents {
|
||||
this.docInfo = this.docModel.docInfoRow;
|
||||
|
||||
this.hasDocTour = Computed.create(this, use =>
|
||||
use(this.docModel.allTableIds.getObservable()).includes('GristDocTour'));
|
||||
use(this.docModel.visibleTableIds.getObservable()).includes('GristDocTour'));
|
||||
|
||||
const defaultViewId = this.docInfo.newDefaultViewId;
|
||||
|
||||
@@ -911,7 +911,7 @@ export class GristDoc extends DisposableWithEvents {
|
||||
* Renames table. Method exposed primarily for tests.
|
||||
*/
|
||||
public async renameTable(tableId: string, newTableName: string) {
|
||||
const tableRec = this.docModel.allTables.all().find(t => t.tableId.peek() === tableId);
|
||||
const tableRec = this.docModel.visibleTables.all().find(t => t.tableId.peek() === tableId);
|
||||
if (!tableRec) {
|
||||
throw new UserError(`No table with id ${tableId}`);
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ export class Importer extends DisposableWithEvents {
|
||||
private _destTables = Computed.create<Array<IOptionFull<DestId>>>(this, (use) => [
|
||||
{value: NEW_TABLE, label: 'New Table'},
|
||||
...(use(this._sourceInfoArray).length > 1 ? [{value: SKIP_TABLE, label: 'Skip'}] : []),
|
||||
...use(this._gristDoc.docModel.allTableIds.getObservable()).map((t) => ({value: t, label: t})),
|
||||
...use(this._gristDoc.docModel.visibleTableIds.getObservable()).map((id) => ({value: id, label: id})),
|
||||
]);
|
||||
|
||||
// Source column labels for the selected import source, keyed by column id.
|
||||
|
||||
@@ -305,7 +305,7 @@ export class GristDocAPIImpl implements GristDocAPI {
|
||||
}
|
||||
|
||||
public async listTables(): Promise<string[]> {
|
||||
// Could perhaps read tableIds from this.gristDoc.docModel.allTableIds.all()?
|
||||
// Could perhaps read tableIds from this.gristDoc.docModel.visibleTableIds.all()?
|
||||
const tables = await this._doc.docComm.fetchTable('_grist_Tables');
|
||||
// Tables the user doesn't have access to are just blanked out.
|
||||
return tables[3].tableId.filter(tableId => tableId !== '') as string[];
|
||||
|
||||
Reference in New Issue
Block a user