mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +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:
parent
8bab8c18fa
commit
a051830aeb
@ -20,10 +20,13 @@ export class DataTables extends Disposable {
|
|||||||
private _view: Observable<string | null>;
|
private _view: Observable<string | null>;
|
||||||
constructor(private _gristDoc: GristDoc) {
|
constructor(private _gristDoc: GristDoc) {
|
||||||
super();
|
super();
|
||||||
// Remove tables that we don't have access to. ACL will remove tableId from those tables.
|
this._tables = Computed.create(this, use => {
|
||||||
this._tables = Computed.create(this, use =>
|
const dataTables = use(_gristDoc.docModel.rawDataTables.getObservable());
|
||||||
use(_gristDoc.docModel.rawTables.getObservable())
|
const summaryTables = use(_gristDoc.docModel.rawSummaryTables.getObservable());
|
||||||
.filter(t => Boolean(use(t.tableId))));
|
// 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.
|
// Get the user id, to remember selected layout on the next visit.
|
||||||
const userId = this._gristDoc.app.topAppModel.appObs.get()?.currentUser?.id ?? 0;
|
const userId = this._gristDoc.app.topAppModel.appObs.get()?.currentUser?.id ?? 0;
|
||||||
this._view = this.autoDispose(localStorageObs(`u=${userId}:raw:viewType`, "list"));
|
this._view = this.autoDispose(localStorageObs(`u=${userId}:raw:viewType`, "list"));
|
||||||
@ -35,7 +38,7 @@ export class DataTables extends Disposable {
|
|||||||
/*************** List section **********/
|
/*************** List section **********/
|
||||||
testId('list'),
|
testId('list'),
|
||||||
cssBetween(
|
cssBetween(
|
||||||
docListHeader('Raw data tables'),
|
docListHeader('Raw Data Tables'),
|
||||||
cssSwitch(
|
cssSwitch(
|
||||||
buttonSelect<any>(
|
buttonSelect<any>(
|
||||||
this._view,
|
this._view,
|
||||||
@ -54,32 +57,13 @@ export class DataTables extends Disposable {
|
|||||||
cssItem(
|
cssItem(
|
||||||
testId('table'),
|
testId('table'),
|
||||||
cssLeft(
|
cssLeft(
|
||||||
dom.domComputed(tableRec.tableId, (tableId) =>
|
dom.domComputed((use) => cssGreenIcon(
|
||||||
cssGreenIcon(
|
use(tableRec.summarySourceTable) !== 0 ? 'PivotLight' : 'TypeTable',
|
||||||
'TypeTable',
|
testId(`table-id-${use(tableRec.tableId)}`)
|
||||||
testId(`table-id-${tableId}`)
|
)),
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
cssMiddle(
|
cssMiddle(
|
||||||
css60(
|
css60(this._tableTitle(tableRec), testId('table-title')),
|
||||||
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(); }),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
css40(
|
css40(
|
||||||
cssIdHoverWrapper(
|
cssIdHoverWrapper(
|
||||||
cssUpperCase("Table id: "),
|
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) {
|
private _menuItems(table: TableRec) {
|
||||||
const {isReadonly, docModel} = this._gristDoc;
|
const {isReadonly, docModel} = this._gristDoc;
|
||||||
return [
|
return [
|
||||||
@ -130,8 +138,8 @@ export class DataTables extends Disposable {
|
|||||||
'Remove',
|
'Remove',
|
||||||
testId('menu-remove'),
|
testId('menu-remove'),
|
||||||
dom.cls('disabled', use => use(isReadonly) || (
|
dom.cls('disabled', use => use(isReadonly) || (
|
||||||
// Can't delete last user table, unless it is a hidden table.
|
// Can't delete last visible table, unless it is a hidden table.
|
||||||
use(docModel.allTables.getObservable()).length <= 1 && !use(table.isHidden)
|
use(docModel.visibleTables.getObservable()).length <= 1 && !use(table.isHidden)
|
||||||
))
|
))
|
||||||
),
|
),
|
||||||
dom.maybe(isReadonly, () => menuText('You do not have edit access to this document')),
|
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) {
|
private _removeTable(t: TableRec) {
|
||||||
const {docModel} = this._gristDoc;
|
const {docModel} = this._gristDoc;
|
||||||
function doRemove() {
|
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.docInfo = this.docModel.docInfoRow;
|
||||||
|
|
||||||
this.hasDocTour = Computed.create(this, use =>
|
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;
|
const defaultViewId = this.docInfo.newDefaultViewId;
|
||||||
|
|
||||||
@ -911,7 +911,7 @@ export class GristDoc extends DisposableWithEvents {
|
|||||||
* Renames table. Method exposed primarily for tests.
|
* Renames table. Method exposed primarily for tests.
|
||||||
*/
|
*/
|
||||||
public async renameTable(tableId: string, newTableName: string) {
|
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) {
|
if (!tableRec) {
|
||||||
throw new UserError(`No table with id ${tableId}`);
|
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) => [
|
private _destTables = Computed.create<Array<IOptionFull<DestId>>>(this, (use) => [
|
||||||
{value: NEW_TABLE, label: 'New Table'},
|
{value: NEW_TABLE, label: 'New Table'},
|
||||||
...(use(this._sourceInfoArray).length > 1 ? [{value: SKIP_TABLE, label: 'Skip'}] : []),
|
...(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.
|
// 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[]> {
|
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');
|
const tables = await this._doc.docComm.fetchTable('_grist_Tables');
|
||||||
// Tables the user doesn't have access to are just blanked out.
|
// Tables the user doesn't have access to are just blanked out.
|
||||||
return tables[3].tableId.filter(tableId => tableId !== '') as string[];
|
return tables[3].tableId.filter(tableId => tableId !== '') as string[];
|
||||||
|
@ -22,7 +22,8 @@ import {urlState} from 'app/client/models/gristUrlState';
|
|||||||
import MetaRowModel from 'app/client/models/MetaRowModel';
|
import MetaRowModel from 'app/client/models/MetaRowModel';
|
||||||
import MetaTableModel from 'app/client/models/MetaTableModel';
|
import MetaTableModel from 'app/client/models/MetaTableModel';
|
||||||
import * as rowset from 'app/client/models/rowset';
|
import * as rowset from 'app/client/models/rowset';
|
||||||
import {isHiddenTable, isRawTable} from 'app/common/isHiddenTable';
|
import {isHiddenTable, isSummaryTable} from 'app/common/isHiddenTable';
|
||||||
|
import {RowFilterFunc} from 'app/common/RowFilterFunc';
|
||||||
import {schema, SchemaTypes} from 'app/common/schema';
|
import {schema, SchemaTypes} from 'app/common/schema';
|
||||||
|
|
||||||
import {ACLRuleRec, createACLRuleRec} from 'app/client/models/entities/ACLRuleRec';
|
import {ACLRuleRec, createACLRuleRec} from 'app/client/models/entities/ACLRuleRec';
|
||||||
@ -126,9 +127,11 @@ export class DocModel {
|
|||||||
|
|
||||||
public docInfoRow: DocInfoRec;
|
public docInfoRow: DocInfoRec;
|
||||||
|
|
||||||
public allTables: KoArray<TableRec>;
|
public visibleTables: KoArray<TableRec>;
|
||||||
public rawTables: KoArray<TableRec>;
|
public rawDataTables: KoArray<TableRec>;
|
||||||
public allTableIds: KoArray<string>;
|
public rawSummaryTables: KoArray<TableRec>;
|
||||||
|
|
||||||
|
public visibleTableIds: KoArray<string>;
|
||||||
|
|
||||||
// A mapping from tableId to DataTableModel for user-defined tables.
|
// A mapping from tableId to DataTableModel for user-defined tables.
|
||||||
public dataTables: {[tableId: string]: DataTableModel} = {};
|
public dataTables: {[tableId: string]: DataTableModel} = {};
|
||||||
@ -161,12 +164,15 @@ export class DocModel {
|
|||||||
|
|
||||||
// An observable array of user-visible tables, sorted by tableId, excluding summary tables.
|
// An observable array of user-visible tables, sorted by tableId, excluding summary tables.
|
||||||
// This is a publicly exposed member.
|
// This is a publicly exposed member.
|
||||||
this.allTables = createUserTablesArray(this.tables);
|
this.visibleTables = createVisibleTablesArray(this.tables);
|
||||||
this.rawTables = createRawTablesArray(this.tables);
|
|
||||||
|
|
||||||
// An observable array of user-visible tableIds. A shortcut mapped from allTables.
|
// Observable arrays of raw data and summary tables, sorted by tableId.
|
||||||
const allTableIds = ko.computed(() => this.allTables.all().map(t => t.tableId()));
|
this.rawDataTables = createRawDataTablesArray(this.tables);
|
||||||
this.allTableIds = koArray.syncedKoArray(allTableIds);
|
this.rawSummaryTables = createRawSummaryTablesArray(this.tables);
|
||||||
|
|
||||||
|
// An observable array of user-visible tableIds. A shortcut mapped from visibleTables.
|
||||||
|
const visibleTableIds = ko.computed(() => this.visibleTables.all().map(t => t.tableId()));
|
||||||
|
this.visibleTableIds = koArray.syncedKoArray(visibleTableIds);
|
||||||
|
|
||||||
// Create an observable array of RowModels for all the data tables. We'll trigger
|
// Create an observable array of RowModels for all the data tables. We'll trigger
|
||||||
// onAddTable/onRemoveTable in response to this array's splice events below.
|
// onAddTable/onRemoveTable in response to this array's splice events below.
|
||||||
@ -219,24 +225,40 @@ export class DocModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an observable array of tables, sorted by tableId.
|
||||||
|
*
|
||||||
|
* An optional `filterFunc` may be specified to filter tables.
|
||||||
|
*/
|
||||||
|
function createTablesArray(
|
||||||
|
tablesModel: MetaTableModel<TableRec>,
|
||||||
|
filterFunc: RowFilterFunc<rowset.RowId> = (_row) => true
|
||||||
|
) {
|
||||||
|
const rowSource = new rowset.FilteredRowSource(filterFunc);
|
||||||
|
rowSource.subscribeTo(tablesModel);
|
||||||
|
// Create an observable RowModel array based on this rowSource, sorted by tableId.
|
||||||
|
return tablesModel._createRowSetModel(rowSource, 'tableId');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to create an observable array of tables, sorted by tableId, and excluding hidden
|
* Returns an observable array of user tables, sorted by tableId, and excluding hidden/summary
|
||||||
* tables.
|
* tables.
|
||||||
*/
|
*/
|
||||||
function createUserTablesArray(tablesModel: MetaTableModel<TableRec>): KoArray<TableRec> {
|
function createVisibleTablesArray(tablesModel: MetaTableModel<TableRec>): KoArray<TableRec> {
|
||||||
const rowSource = new rowset.FilteredRowSource(r => !isHiddenTable(tablesModel.tableData, r));
|
return createTablesArray(tablesModel, r => !isHiddenTable(tablesModel.tableData, r));
|
||||||
rowSource.subscribeTo(tablesModel);
|
|
||||||
// Create an observable RowModel array based on this rowSource, sorted by tableId.
|
|
||||||
return tablesModel._createRowSetModel(rowSource, 'tableId');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to create an observable array of tables, sorted by tableId, and excluding summary tables.
|
* Returns an observable array of raw data tables, sorted by tableId, and excluding summary
|
||||||
|
* tables.
|
||||||
*/
|
*/
|
||||||
function createRawTablesArray(tablesModel: MetaTableModel<TableRec>): KoArray<TableRec> {
|
function createRawDataTablesArray(tablesModel: MetaTableModel<TableRec>): KoArray<TableRec> {
|
||||||
const rowSource = new rowset.FilteredRowSource(r => isRawTable(tablesModel.tableData, r));
|
return createTablesArray(tablesModel, r => !isSummaryTable(tablesModel.tableData, r));
|
||||||
rowSource.subscribeTo(tablesModel);
|
}
|
||||||
// Create an observable RowModel array based on this rowSource, sorted by tableId.
|
|
||||||
return tablesModel._createRowSetModel(rowSource, 'tableId');
|
/**
|
||||||
|
* Returns an observable array of raw summary tables, sorted by tableId.
|
||||||
|
*/
|
||||||
|
function createRawSummaryTablesArray(tablesModel: MetaTableModel<TableRec>): KoArray<TableRec> {
|
||||||
|
return createTablesArray(tablesModel, r => isSummaryTable(tablesModel.tableData, r));
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ class FinderImpl implements IFinder {
|
|||||||
// If we are on a raw view page, pretend that we are looking at true pages.
|
// If we are on a raw view page, pretend that we are looking at true pages.
|
||||||
if ('data' === this._gristDoc.activeViewId.get()) {
|
if ('data' === this._gristDoc.activeViewId.get()) {
|
||||||
// Get all raw sections.
|
// Get all raw sections.
|
||||||
const rawSections = this._gristDoc.docModel.allTables.peek()
|
const rawSections = this._gristDoc.docModel.visibleTables.peek()
|
||||||
// Filter out those we don't have permissions to see (through ACL-tableId will be empty).
|
// Filter out those we don't have permissions to see (through ACL-tableId will be empty).
|
||||||
.filter(t => Boolean(t.tableId.peek()))
|
.filter(t => Boolean(t.tableId.peek()))
|
||||||
// sort in order that is the same as on the raw data list page,
|
// sort in order that is the same as on the raw data list page,
|
||||||
|
@ -124,7 +124,7 @@ export function createColumnRec(this: ColumnRec, docModel: DocModel): void {
|
|||||||
// Returns the rowModel for the referenced table, or null, if this is not a reference column.
|
// Returns the rowModel for the referenced table, or null, if this is not a reference column.
|
||||||
this.refTable = ko.pureComputed(() => {
|
this.refTable = ko.pureComputed(() => {
|
||||||
const refTableId = getReferencedTableId(this.type() || "");
|
const refTableId = getReferencedTableId(this.type() || "");
|
||||||
return refTableId ? docModel.allTables.all().find(t => t.tableId() === refTableId) || null : null;
|
return refTableId ? docModel.visibleTables.all().find(t => t.tableId() === refTableId) || null : null;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Helper for Reference/ReferenceList columns, which returns a formatter according to the visibleCol
|
// Helper for Reference/ReferenceList columns, which returns a formatter according to the visibleCol
|
||||||
|
@ -13,7 +13,7 @@ export function createPageRec(this: PageRec, docModel: DocModel): void {
|
|||||||
const name = this.view().name();
|
const name = this.view().name();
|
||||||
const isTableHidden = () => {
|
const isTableHidden = () => {
|
||||||
const viewId = this.view().id();
|
const viewId = this.view().id();
|
||||||
const tables = docModel.rawTables.all();
|
const tables = docModel.rawDataTables.all();
|
||||||
const primaryTable = tables.find(t => t.primaryViewId() === viewId);
|
const primaryTable = tables.find(t => t.primaryViewId() === viewId);
|
||||||
return !!primaryTable && primaryTable.isHidden();
|
return !!primaryTable && primaryTable.isHidden();
|
||||||
};
|
};
|
||||||
|
@ -30,6 +30,9 @@ export interface TableRec extends IRowModel<"_grist_Tables"> {
|
|||||||
tableName: modelUtil.KoSaveableObservable<string>;
|
tableName: modelUtil.KoSaveableObservable<string>;
|
||||||
// Table name with a default value (which is tableId).
|
// Table name with a default value (which is tableId).
|
||||||
tableNameDef: modelUtil.KoSaveableObservable<string>;
|
tableNameDef: modelUtil.KoSaveableObservable<string>;
|
||||||
|
// Like tableNameDef, but formatted to be more suitable for displaying to
|
||||||
|
// users (e.g. including group columns for summary tables).
|
||||||
|
formattedTableName: ko.PureComputed<string>;
|
||||||
// If user can select this table in various places.
|
// If user can select this table in various places.
|
||||||
// Note: Some hidden tables can still be visible on RawData view.
|
// Note: Some hidden tables can still be visible on RawData view.
|
||||||
isHidden: ko.Computed<boolean>;
|
isHidden: ko.Computed<boolean>;
|
||||||
@ -114,4 +117,9 @@ export function createTableRec(this: TableRec, docModel: DocModel): void {
|
|||||||
return table.tableId() || '';
|
return table.tableId() || '';
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
this.formattedTableName = ko.pureComputed(() => {
|
||||||
|
return this.summarySourceTable()
|
||||||
|
? `${this.tableNameDef()} ${this.groupDesc()}`
|
||||||
|
: this.tableNameDef();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ export function buildPageWidgetPicker(
|
|||||||
onSave: ISaveFunc,
|
onSave: ISaveFunc,
|
||||||
options: IOptions = {}) {
|
options: IOptions = {}) {
|
||||||
|
|
||||||
const tables = fromKo(docModel.allTables.getObservable());
|
const tables = fromKo(docModel.visibleTables.getObservable());
|
||||||
const columns = fromKo(docModel.columns.createAllRowsModel('parentPos').getObservable());
|
const columns = fromKo(docModel.columns.createAllRowsModel('parentPos').getObservable());
|
||||||
|
|
||||||
// default value for when it is omitted
|
// default value for when it is omitted
|
||||||
|
@ -300,10 +300,16 @@ export class RightPanel extends Disposable {
|
|||||||
return dom.maybe(viewConfigTab, (vct) => [
|
return dom.maybe(viewConfigTab, (vct) => [
|
||||||
this._disableIfReadonly(),
|
this._disableIfReadonly(),
|
||||||
cssLabel(dom.text(use => use(activeSection.isRaw) ? 'DATA TABLE NAME' : 'WIDGET TITLE'),
|
cssLabel(dom.text(use => use(activeSection.isRaw) ? 'DATA TABLE NAME' : 'WIDGET TITLE'),
|
||||||
dom.style('margin-bottom', '14px')),
|
dom.style('margin-bottom', '14px'),
|
||||||
|
),
|
||||||
cssRow(cssTextInput(
|
cssRow(cssTextInput(
|
||||||
Computed.create(owner, (use) => use(activeSection.titleDef)),
|
Computed.create(owner, (use) => use(activeSection.titleDef)),
|
||||||
val => activeSection.titleDef.saveOnly(val),
|
val => activeSection.titleDef.saveOnly(val),
|
||||||
|
dom.boolAttr('disabled', use => {
|
||||||
|
const isRawTable = use(activeSection.isRaw);
|
||||||
|
const isSummaryTable = use(use(activeSection.table).summarySourceTable) !== 0;
|
||||||
|
return isRawTable && isSummaryTable;
|
||||||
|
}),
|
||||||
testId('right-widget-title')
|
testId('right-widget-title')
|
||||||
)),
|
)),
|
||||||
|
|
||||||
@ -753,4 +759,10 @@ const cssListItem = styled('li', `
|
|||||||
|
|
||||||
export const cssTextInput = styled(textInput, `
|
export const cssTextInput = styled(textInput, `
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
color: ${colors.slate};
|
||||||
|
background-color: ${colors.lightGrey};
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
|
@ -51,7 +51,7 @@ export function tools(owner: Disposable, gristDoc: GristDoc, leftPanelOpen: Obse
|
|||||||
cssPageEntry.cls('-selected', (use) => use(gristDoc.activeViewId) === 'data'),
|
cssPageEntry.cls('-selected', (use) => use(gristDoc.activeViewId) === 'data'),
|
||||||
cssPageLink(
|
cssPageLink(
|
||||||
cssPageIcon('Database'),
|
cssPageIcon('Database'),
|
||||||
cssLinkText('Raw data'),
|
cssLinkText('Raw Data'),
|
||||||
testId('raw'),
|
testId('raw'),
|
||||||
urlState().setLinkUrl({docPage: 'data'})
|
urlState().setLinkUrl({docPage: 'data'})
|
||||||
)
|
)
|
||||||
|
@ -88,6 +88,7 @@ export type IconName = "ChartArea" |
|
|||||||
"PinBig" |
|
"PinBig" |
|
||||||
"PinSmall" |
|
"PinSmall" |
|
||||||
"Pivot" |
|
"Pivot" |
|
||||||
|
"PivotLight" |
|
||||||
"Plus" |
|
"Plus" |
|
||||||
"Public" |
|
"Public" |
|
||||||
"PublicColor" |
|
"PublicColor" |
|
||||||
@ -213,6 +214,7 @@ export const IconList: IconName[] = ["ChartArea",
|
|||||||
"PinBig",
|
"PinBig",
|
||||||
"PinSmall",
|
"PinSmall",
|
||||||
"Pivot",
|
"Pivot",
|
||||||
|
"PivotLight",
|
||||||
"Plus",
|
"Plus",
|
||||||
"Public",
|
"Public",
|
||||||
"PublicColor",
|
"PublicColor",
|
||||||
|
@ -289,7 +289,7 @@ export class FieldBuilder extends Disposable {
|
|||||||
// Builds the reference type table selector. Built when the column is type reference.
|
// Builds the reference type table selector. Built when the column is type reference.
|
||||||
public _buildRefTableSelect() {
|
public _buildRefTableSelect() {
|
||||||
const allTables = Computed.create(null, (use) =>
|
const allTables = Computed.create(null, (use) =>
|
||||||
use(this._docModel.allTableIds.getObservable()).map(tableId => ({
|
use(this._docModel.visibleTableIds.getObservable()).map(tableId => ({
|
||||||
value: tableId,
|
value: tableId,
|
||||||
label: tableId,
|
label: tableId,
|
||||||
icon: 'FieldTable' as const
|
icon: 'FieldTable' as const
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
|
import {TableData} from 'app/common/TableData';
|
||||||
import {UIRowId} from 'app/common/UIRowId';
|
import {UIRowId} from 'app/common/UIRowId';
|
||||||
import {TableData} from "./TableData";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether a table identified by the rowId of its metadata record, should normally be
|
* Return whether a table (identified by the rowId of its metadata record) should
|
||||||
* hidden from the user (e.g. as an option in the page-widget picker).
|
* normally be hidden from the user (e.g. as an option in the page-widget picker).
|
||||||
*/
|
*/
|
||||||
export function isHiddenTable(tablesData: TableData, tableRef: UIRowId): boolean {
|
export function isHiddenTable(tablesData: TableData, tableRef: UIRowId): boolean {
|
||||||
const tableId = tablesData.getValue(tableRef, 'tableId') as string|undefined;
|
const tableId = tablesData.getValue(tableRef, 'tableId') as string|undefined;
|
||||||
return !isRawTable(tablesData, tableRef) || Boolean(tableId?.startsWith('GristHidden'));
|
return isSummaryTable(tablesData, tableRef) || Boolean(tableId?.startsWith('GristHidden'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether a table identified by the rowId of its metadata record should be visible on Raw Data page.
|
* Return whether a table (identified by the rowId of its metadata record) is a
|
||||||
|
* summary table.
|
||||||
*/
|
*/
|
||||||
export function isRawTable(tablesData: TableData, tableRef: UIRowId): boolean {
|
export function isSummaryTable(tablesData: TableData, tableRef: UIRowId): boolean {
|
||||||
return tablesData.getValue(tableRef, 'summarySourceTable') === 0;
|
return tablesData.getValue(tableRef, 'summarySourceTable') !== 0;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { GristObjCode } from "app/plugin/GristData";
|
|||||||
|
|
||||||
// tslint:disable:object-literal-key-quotes
|
// tslint:disable:object-literal-key-quotes
|
||||||
|
|
||||||
export const SCHEMA_VERSION = 29;
|
export const SCHEMA_VERSION = 30;
|
||||||
|
|
||||||
export const schema = {
|
export const schema = {
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ export const GRIST_DOC_SQL = `
|
|||||||
PRAGMA foreign_keys=OFF;
|
PRAGMA foreign_keys=OFF;
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
||||||
INSERT INTO _grist_DocInfo VALUES(1,'','','',29,'','');
|
INSERT INTO _grist_DocInfo VALUES(1,'','','',30,'','');
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Imports" (id INTEGER PRIMARY KEY, "tableRef" INTEGER DEFAULT 0, "origFileName" TEXT DEFAULT '', "parseFormula" TEXT DEFAULT '', "delimiter" TEXT DEFAULT '', "doublequote" BOOLEAN DEFAULT 0, "escapechar" TEXT DEFAULT '', "quotechar" TEXT DEFAULT '', "skipinitialspace" BOOLEAN DEFAULT 0, "encoding" TEXT DEFAULT '', "hasHeaders" BOOLEAN DEFAULT 0);
|
CREATE TABLE IF NOT EXISTS "_grist_Imports" (id INTEGER PRIMARY KEY, "tableRef" INTEGER DEFAULT 0, "origFileName" TEXT DEFAULT '', "parseFormula" TEXT DEFAULT '', "delimiter" TEXT DEFAULT '', "doublequote" BOOLEAN DEFAULT 0, "escapechar" TEXT DEFAULT '', "quotechar" TEXT DEFAULT '', "skipinitialspace" BOOLEAN DEFAULT 0, "encoding" TEXT DEFAULT '', "hasHeaders" BOOLEAN DEFAULT 0);
|
||||||
@ -42,7 +42,7 @@ export const GRIST_DOC_WITH_TABLE1_SQL = `
|
|||||||
PRAGMA foreign_keys=OFF;
|
PRAGMA foreign_keys=OFF;
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
||||||
INSERT INTO _grist_DocInfo VALUES(1,'','','',29,'','');
|
INSERT INTO _grist_DocInfo VALUES(1,'','','',30,'','');
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
||||||
INSERT INTO _grist_Tables VALUES(1,'Table1',1,0,0,2);
|
INSERT INTO _grist_Tables VALUES(1,'Table1',1,0,0,2);
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
||||||
|
@ -73,8 +73,13 @@ class MetaTableExtras(object):
|
|||||||
if rec.summarySourceTable else None)
|
if rec.summarySourceTable else None)
|
||||||
|
|
||||||
def setAutoRemove(rec, table):
|
def setAutoRemove(rec, table):
|
||||||
"""Marks the table for removal if it's a summary table with no more view sections."""
|
"""
|
||||||
table.docmodel.setAutoRemove(rec, rec.summarySourceTable and not rec.viewSections)
|
Marks the table for removal if it's a summary table with no more (non-raw) view sections.
|
||||||
|
"""
|
||||||
|
is_summary_table = rec.summarySourceTable
|
||||||
|
view_sections_table = table.docmodel.get_table('_grist_Views_section')
|
||||||
|
has_view_sections = view_sections_table.lookupOne(isRaw=False, tableRef=rec.id)
|
||||||
|
table.docmodel.setAutoRemove(rec, is_summary_table and not has_view_sections)
|
||||||
|
|
||||||
|
|
||||||
class _grist_Tables_column(object):
|
class _grist_Tables_column(object):
|
||||||
|
@ -960,3 +960,57 @@ def migration29(tdset):
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
return tdset.apply_doc_actions(doc_actions)
|
return tdset.apply_doc_actions(doc_actions)
|
||||||
|
|
||||||
|
@migration(schema_version=30)
|
||||||
|
def migration30(tdset):
|
||||||
|
"""
|
||||||
|
Add raw view sections for each summary table. This is similar to migration 26, but for
|
||||||
|
summary tables instead of user tables.
|
||||||
|
"""
|
||||||
|
doc_actions = []
|
||||||
|
|
||||||
|
tables = list(actions.transpose_bulk_action(tdset.all_tables["_grist_Tables"]))
|
||||||
|
columns = list(actions.transpose_bulk_action(tdset.all_tables["_grist_Tables_column"]))
|
||||||
|
|
||||||
|
new_view_section_id = next_id(tdset, "_grist_Views_section")
|
||||||
|
|
||||||
|
for table in sorted(tables, key=lambda t: t.tableId):
|
||||||
|
if not table.summarySourceTable:
|
||||||
|
continue
|
||||||
|
|
||||||
|
table_columns = [
|
||||||
|
col for col in columns
|
||||||
|
if table.id == col.parentId and is_visible_column(col.colId)
|
||||||
|
]
|
||||||
|
table_columns.sort(key=lambda c: c.parentPos)
|
||||||
|
fields = {
|
||||||
|
"parentId": [new_view_section_id] * len(table_columns),
|
||||||
|
"colRef": [col.id for col in table_columns],
|
||||||
|
"parentPos": [col.parentPos for col in table_columns],
|
||||||
|
}
|
||||||
|
field_ids = [None] * len(table_columns)
|
||||||
|
|
||||||
|
doc_actions += [
|
||||||
|
actions.AddRecord(
|
||||||
|
"_grist_Views_section", new_view_section_id, {
|
||||||
|
"tableRef": table.id,
|
||||||
|
"parentId": 0,
|
||||||
|
"parentKey": "record",
|
||||||
|
"title": "",
|
||||||
|
"defaultWidth": 100,
|
||||||
|
"borderWidth": 1,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
actions.UpdateRecord(
|
||||||
|
"_grist_Tables", table.id, {
|
||||||
|
"rawViewSectionRef": new_view_section_id,
|
||||||
|
})
|
||||||
|
,
|
||||||
|
actions.BulkAddRecord(
|
||||||
|
"_grist_Views_section_field", field_ids, fields
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
new_view_section_id += 1
|
||||||
|
|
||||||
|
return tdset.apply_doc_actions(doc_actions)
|
||||||
|
@ -15,7 +15,7 @@ import six
|
|||||||
|
|
||||||
import actions
|
import actions
|
||||||
|
|
||||||
SCHEMA_VERSION = 29
|
SCHEMA_VERSION = 30
|
||||||
|
|
||||||
def make_column(col_id, col_type, formula='', isFormula=False):
|
def make_column(col_id, col_type, formula='', isFormula=False):
|
||||||
return {
|
return {
|
||||||
|
@ -205,7 +205,8 @@ class SummaryActions(object):
|
|||||||
result = self.useractions.doAddTable(
|
result = self.useractions.doAddTable(
|
||||||
encode_summary_table_name(source_table.tableId),
|
encode_summary_table_name(source_table.tableId),
|
||||||
[_get_colinfo_dict(ci, with_id=True) for ci in groupby_colinfo + formula_colinfo],
|
[_get_colinfo_dict(ci, with_id=True) for ci in groupby_colinfo + formula_colinfo],
|
||||||
summarySourceTableRef=source_table.id)
|
summarySourceTableRef=source_table.id,
|
||||||
|
raw_section=True)
|
||||||
summary_table = self.docmodel.tables.table.get_record(result['id'])
|
summary_table = self.docmodel.tables.table.get_record(result['id'])
|
||||||
created = True
|
created = True
|
||||||
# Note that in this case, _get_or_add_columns() below should not add any new columns,
|
# Note that in this case, _get_or_add_columns() below should not add any new columns,
|
||||||
|
@ -228,10 +228,10 @@ class TestColumnActions(test_engine.EngineTestCase):
|
|||||||
Field(11, colRef=16),
|
Field(11, colRef=16),
|
||||||
Field(12, colRef=17),
|
Field(12, colRef=17),
|
||||||
]),
|
]),
|
||||||
Section(5, parentKey="record", tableRef=3, fields=[
|
Section(6, parentKey="record", tableRef=3, fields=[
|
||||||
Field(13, colRef=18),
|
Field(16, colRef=18),
|
||||||
Field(14, colRef=20),
|
Field(17, colRef=20),
|
||||||
Field(15, colRef=21),
|
Field(18, colRef=21),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
View(2, sections=[
|
View(2, sections=[
|
||||||
@ -315,10 +315,10 @@ class TestColumnActions(test_engine.EngineTestCase):
|
|||||||
Field(10, colRef=15),
|
Field(10, colRef=15),
|
||||||
Field(12, colRef=17),
|
Field(12, colRef=17),
|
||||||
]),
|
]),
|
||||||
Section(5, parentKey="record", tableRef=3, fields=[
|
Section(6, parentKey="record", tableRef=3, fields=[
|
||||||
Field(13, colRef=18),
|
Field(16, colRef=18),
|
||||||
Field(14, colRef=20),
|
Field(17, colRef=20),
|
||||||
Field(15, colRef=21),
|
Field(18, colRef=21),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
View(2, sections=[
|
View(2, sections=[
|
||||||
@ -372,9 +372,9 @@ class TestColumnActions(test_engine.EngineTestCase):
|
|||||||
Field(10, colRef=15),
|
Field(10, colRef=15),
|
||||||
Field(12, colRef=17),
|
Field(12, colRef=17),
|
||||||
]),
|
]),
|
||||||
Section(5, parentKey="record", tableRef=4, fields=[
|
Section(6, parentKey="record", tableRef=4, fields=[
|
||||||
Field(14, colRef=23),
|
Field(17, colRef=23),
|
||||||
Field(15, colRef=24),
|
Field(18, colRef=24),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
View(2, sections=[
|
View(2, sections=[
|
||||||
|
@ -126,9 +126,9 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
formula="SUM($group.amount)"),
|
formula="SUM($group.amount)"),
|
||||||
])
|
])
|
||||||
summary_view1 = View(2, sections=[
|
summary_view1 = View(2, sections=[
|
||||||
Section(2, parentKey="record", tableRef=2, fields=[
|
Section(3, parentKey="record", tableRef=2, fields=[
|
||||||
Field(4, colRef=15),
|
Field(6, colRef=15),
|
||||||
Field(5, colRef=16),
|
Field(7, colRef=16),
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
self.assertTables([self.starting_table, summary_table1])
|
self.assertTables([self.starting_table, summary_table1])
|
||||||
@ -156,10 +156,10 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
formula="SUM($group.amount)"),
|
formula="SUM($group.amount)"),
|
||||||
])
|
])
|
||||||
summary_view2 = View(3, sections=[
|
summary_view2 = View(3, sections=[
|
||||||
Section(3, parentKey="record", tableRef=3, fields=[
|
Section(5, parentKey="record", tableRef=3, fields=[
|
||||||
Field(6, colRef=17),
|
Field(11, colRef=17),
|
||||||
Field(7, colRef=19),
|
Field(12, colRef=19),
|
||||||
Field(8, colRef=20),
|
Field(13, colRef=20),
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
self.assertTables([self.starting_table, summary_table1, summary_table2])
|
self.assertTables([self.starting_table, summary_table1, summary_table2])
|
||||||
@ -197,11 +197,11 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
formula="SUM($group.amount)"),
|
formula="SUM($group.amount)"),
|
||||||
])
|
])
|
||||||
summary_view3 = View(4, sections=[
|
summary_view3 = View(4, sections=[
|
||||||
Section(4, parentKey="record", tableRef=4, fields=[
|
Section(7, parentKey="record", tableRef=4, fields=[
|
||||||
Field(9, colRef=21),
|
Field(18, colRef=21),
|
||||||
Field(10, colRef=22),
|
Field(19, colRef=22),
|
||||||
Field(11, colRef=24),
|
Field(20, colRef=24),
|
||||||
Field(12, colRef=25),
|
Field(21, colRef=25),
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
self.assertTables([self.starting_table, summary_table1, summary_table2, summary_table3])
|
self.assertTables([self.starting_table, summary_table1, summary_table2, summary_table3])
|
||||||
@ -281,11 +281,11 @@ class Address:
|
|||||||
formula="SUM($group.amount)"),
|
formula="SUM($group.amount)"),
|
||||||
])
|
])
|
||||||
summary_view = View(1, sections=[
|
summary_view = View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=2, fields=[
|
Section(2, parentKey="record", tableRef=2, fields=[
|
||||||
Field(1, colRef=14),
|
Field(5, colRef=14),
|
||||||
Field(2, colRef=15),
|
Field(6, colRef=15),
|
||||||
Field(3, colRef=17),
|
Field(7, colRef=17),
|
||||||
Field(4, colRef=18),
|
Field(8, colRef=18),
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
self.assertTables([self.starting_table, summary_table])
|
self.assertTables([self.starting_table, summary_table])
|
||||||
@ -296,19 +296,19 @@ class Address:
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [12,11], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [12,11], None])
|
||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
||||||
summary_view2 = View(2, sections=[
|
summary_view2 = View(2, sections=[
|
||||||
Section(2, parentKey="record", tableRef=2, fields=[
|
Section(3, parentKey="record", tableRef=2, fields=[
|
||||||
Field(5, colRef=15),
|
Field(9, colRef=15),
|
||||||
Field(6, colRef=14),
|
Field(10, colRef=14),
|
||||||
Field(7, colRef=17),
|
Field(11, colRef=17),
|
||||||
Field(8, colRef=18),
|
Field(12, colRef=18),
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
summary_view3 = View(3, sections=[
|
summary_view3 = View(3, sections=[
|
||||||
Section(3, parentKey="record", tableRef=2, fields=[
|
Section(4, parentKey="record", tableRef=2, fields=[
|
||||||
Field(9, colRef=14),
|
Field(13, colRef=14),
|
||||||
Field(10, colRef=15),
|
Field(14, colRef=15),
|
||||||
Field(11, colRef=17),
|
Field(15, colRef=17),
|
||||||
Field(12, colRef=18),
|
Field(16, colRef=18),
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
# Verify that we have a new view, but are reusing the table.
|
# Verify that we have a new view, but are reusing the table.
|
||||||
|
@ -83,11 +83,13 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
# We should now have two sections for table 2 (the one with two group-by fields).
|
# We should now have three sections for table 2 (the one with two group-by fields). One for
|
||||||
|
# the raw summary table view, and two for the non-raw views.
|
||||||
self.assertTableData('_grist_Views_section', cols="subset", data=[
|
self.assertTableData('_grist_Views_section', cols="subset", data=[
|
||||||
["id", "parentId", "tableRef"],
|
["id", "parentId", "tableRef"],
|
||||||
[1, 1, 2],
|
[1, 0, 2],
|
||||||
[5, 5, 2],
|
[2, 1, 2],
|
||||||
|
[9, 5, 2],
|
||||||
], rows=lambda r: r.tableRef.id == 2)
|
], rows=lambda r: r.tableRef.id == 2)
|
||||||
self.assertTableData('_grist_Views_section_field', cols="subset", data=[
|
self.assertTableData('_grist_Views_section_field', cols="subset", data=[
|
||||||
["id", "parentId", "colRef"],
|
["id", "parentId", "colRef"],
|
||||||
@ -95,11 +97,11 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[2, 1, 15],
|
[2, 1, 15],
|
||||||
[3, 1, 17],
|
[3, 1, 17],
|
||||||
[4, 1, 18],
|
[4, 1, 18],
|
||||||
[8, 1, 23],
|
[15, 1, 23],
|
||||||
[16, 5, 14],
|
[17, 5, 24],
|
||||||
[17, 5, 15],
|
[18, 5, 26],
|
||||||
[18, 5, 17],
|
[19, 5, 27],
|
||||||
[19, 5, 18], # new section doesn't automatically get 'average' column
|
[20, 5, 28], # new section doesn't automatically get 'average' column
|
||||||
], rows=lambda r: r.parentId.id in {1,5})
|
], rows=lambda r: r.parentId.id in {1,5})
|
||||||
|
|
||||||
|
|
||||||
@ -433,11 +435,11 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=2, fields=[
|
Section(2, parentKey="record", tableRef=2, fields=[
|
||||||
Field(1, colRef=14),
|
Field(5, colRef=14),
|
||||||
Field(2, colRef=15),
|
Field(6, colRef=15),
|
||||||
Field(3, colRef=17),
|
Field(7, colRef=17),
|
||||||
Field(4, colRef=18),
|
Field(8, colRef=18),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
||||||
@ -451,7 +453,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Now change the group-by to just one of the columns ('state')
|
# Now change the group-by to just one of the columns ('state')
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 1, [12]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [12]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #2 is gone at this point, since it's unused.
|
# Note that Table #2 is gone at this point, since it's unused.
|
||||||
@ -463,10 +465,10 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=3, fields=[
|
Section(2, parentKey="record", tableRef=3, fields=[
|
||||||
Field(2, colRef=19),
|
Field(6, colRef=19),
|
||||||
Field(3, colRef=21),
|
Field(7, colRef=21),
|
||||||
Field(4, colRef=22),
|
Field(8, colRef=22),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="subset", data=[
|
self.assertTableData('GristSummary_7_Address2', cols="subset", data=[
|
||||||
@ -486,7 +488,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Change group-by to a different single column ('city')
|
# Change group-by to a different single column ('city')
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 1, [11]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [11]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #3 is gone at this point, since it's unused.
|
# Note that Table #3 is gone at this point, since it's unused.
|
||||||
@ -498,10 +500,10 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=4, fields=[
|
Section(2, parentKey="record", tableRef=4, fields=[
|
||||||
Field(5, colRef=23),
|
Field(15, colRef=23),
|
||||||
Field(3, colRef=25),
|
Field(7, colRef=25),
|
||||||
Field(4, colRef=26),
|
Field(8, colRef=26),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
||||||
@ -525,7 +527,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Change group-by to no columns (totals)
|
# Change group-by to no columns (totals)
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 1, []])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, []])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #4 is gone at this point, since it's unused.
|
# Note that Table #4 is gone at this point, since it's unused.
|
||||||
@ -536,9 +538,9 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=5, fields=[
|
Section(2, parentKey="record", tableRef=5, fields=[
|
||||||
Field(3, colRef=28),
|
Field(7, colRef=28),
|
||||||
Field(4, colRef=29),
|
Field(8, colRef=29),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="subset", data=[
|
self.assertTableData('GristSummary_7_Address2', cols="subset", data=[
|
||||||
@ -548,7 +550,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address2'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address2'])
|
||||||
|
|
||||||
# Back to full circle, but with group-by columns differently arranged.
|
# Back to full circle, but with group-by columns differently arranged.
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 1, [12,11]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [12,11]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #5 is gone at this point, since it's unused.
|
# Note that Table #5 is gone at this point, since it's unused.
|
||||||
@ -561,11 +563,11 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=6, fields=[
|
Section(2, parentKey="record", tableRef=6, fields=[
|
||||||
Field(5, colRef=30),
|
Field(22, colRef=30),
|
||||||
Field(6, colRef=31),
|
Field(23, colRef=31),
|
||||||
Field(3, colRef=33),
|
Field(7, colRef=33),
|
||||||
Field(4, colRef=34),
|
Field(8, colRef=34),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
||||||
@ -595,23 +597,23 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=6, fields=[
|
|
||||||
Field(5, colRef=30),
|
|
||||||
Field(6, colRef=31),
|
|
||||||
Field(3, colRef=33),
|
|
||||||
Field(4, colRef=34),
|
|
||||||
]),
|
|
||||||
Section(2, parentKey="record", tableRef=6, fields=[
|
Section(2, parentKey="record", tableRef=6, fields=[
|
||||||
Field(7, colRef=31),
|
Field(22, colRef=30),
|
||||||
Field(8, colRef=30),
|
Field(23, colRef=31),
|
||||||
Field(9, colRef=33),
|
Field(7, colRef=33),
|
||||||
Field(10, colRef=34),
|
Field(8, colRef=34),
|
||||||
|
]),
|
||||||
|
Section(7, parentKey="record", tableRef=6, fields=[
|
||||||
|
Field(24, colRef=31),
|
||||||
|
Field(25, colRef=30),
|
||||||
|
Field(26, colRef=33),
|
||||||
|
Field(27, colRef=34),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
||||||
|
|
||||||
# Change one view section, and ensure there are now two summary tables.
|
# Change one view section, and ensure there are now two summary tables.
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 2, []])
|
self.apply_user_action(["UpdateSummaryViewSection", 7, []])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(6, "GristSummary_7_Address", 0, 1, columns=[
|
Table(6, "GristSummary_7_Address", 0, 1, columns=[
|
||||||
@ -628,22 +630,22 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=6, fields=[
|
Section(2, parentKey="record", tableRef=6, fields=[
|
||||||
Field(5, colRef=30),
|
Field(22, colRef=30),
|
||||||
Field(6, colRef=31),
|
Field(23, colRef=31),
|
||||||
Field(3, colRef=33),
|
Field(7, colRef=33),
|
||||||
Field(4, colRef=34),
|
Field(8, colRef=34),
|
||||||
]),
|
]),
|
||||||
Section(2, parentKey="record", tableRef=7, fields=[
|
Section(7, parentKey="record", tableRef=7, fields=[
|
||||||
Field(9, colRef=36),
|
Field(26, colRef=36),
|
||||||
Field(10, colRef=37),
|
Field(27, colRef=37),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address',
|
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address',
|
||||||
'#summary#GristSummary_7_Address2'])
|
'#summary#GristSummary_7_Address2'])
|
||||||
|
|
||||||
# Delete one view section, and see that the summary table is gone.
|
# Delete one view section, and see that the summary table is gone.
|
||||||
self.apply_user_action(["RemoveViewSection", 2])
|
self.apply_user_action(["RemoveViewSection", 7])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #7 is gone at this point, since it's now unused.
|
# Note that Table #7 is gone at this point, since it's now unused.
|
||||||
@ -656,18 +658,18 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=6, fields=[
|
Section(2, parentKey="record", tableRef=6, fields=[
|
||||||
Field(5, colRef=30),
|
Field(22, colRef=30),
|
||||||
Field(6, colRef=31),
|
Field(23, colRef=31),
|
||||||
Field(3, colRef=33),
|
Field(7, colRef=33),
|
||||||
Field(4, colRef=34),
|
Field(8, colRef=34),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
||||||
|
|
||||||
# Change the section to add and then remove the "amount" to the group-by column; check that
|
# Change the section to add and then remove the "amount" to the group-by column; check that
|
||||||
# column "amount" was correctly restored
|
# column "amount" was correctly restored
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 1, [11, 12, 13]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [11, 12, 13]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(7, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(7, "GristSummary_7_Address2", 0, 1, columns=[
|
||||||
@ -679,14 +681,14 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=7, fields=[
|
Section(2, parentKey="record", tableRef=7, fields=[
|
||||||
Field(6, colRef=35),
|
Field(23, colRef=35),
|
||||||
Field(5, colRef=36),
|
Field(22, colRef=36),
|
||||||
Field(7, colRef=37),
|
Field(28, colRef=37),
|
||||||
Field(3, colRef=39),
|
Field(7, colRef=39),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 1, [11,12]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [11,12]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(8, "GristSummary_7_Address", 0, 1, columns=[
|
Table(8, "GristSummary_7_Address", 0, 1, columns=[
|
||||||
@ -699,18 +701,18 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=8, fields=[
|
Section(2, parentKey="record", tableRef=8, fields=[
|
||||||
Field(6, colRef=40),
|
Field(23, colRef=40),
|
||||||
Field(5, colRef=41),
|
Field(22, colRef=41),
|
||||||
Field(7, colRef=42),
|
Field(28, colRef=42),
|
||||||
Field(3, colRef=44),
|
Field(7, colRef=44),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
|
|
||||||
# Hide a formula and update group by columns; check that the formula columns had not been
|
# Hide a formula and update group by columns; check that the formula columns had not been
|
||||||
# deleted
|
# deleted
|
||||||
self.apply_user_action(['RemoveRecord', '_grist_Views_section_field', 7])
|
self.apply_user_action(['RemoveRecord', '_grist_Views_section_field', 7])
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 1, [11]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [11]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(9, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(9, "GristSummary_7_Address2", 0, 1, columns=[
|
||||||
@ -721,9 +723,9 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=9, fields=[
|
Section(2, parentKey="record", tableRef=9, fields=[
|
||||||
Field(6, colRef=45),
|
Field(23, colRef=45),
|
||||||
Field(3, colRef=48),
|
Field(28, colRef=46),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
|
|
||||||
@ -754,11 +756,11 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=2, fields=[
|
Section(2, parentKey="record", tableRef=2, fields=[
|
||||||
Field(1, colRef=14),
|
Field(4, colRef=14),
|
||||||
Field(2, colRef=16),
|
Field(5, colRef=16),
|
||||||
Field(3, colRef=17),
|
Field(6, colRef=17),
|
||||||
Field(4, colRef=18),
|
Field(8, colRef=18),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
||||||
@ -770,7 +772,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Change the section to add "city" as a group-by column; check that the formula is gone.
|
# Change the section to add "city" as a group-by column; check that the formula is gone.
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 1, [11,12]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [11,12]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
||||||
@ -782,12 +784,12 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=3, fields=[
|
Section(2, parentKey="record", tableRef=3, fields=[
|
||||||
# We requested 'city' to come before 'state', check that this is the case.
|
# We requested 'city' to come before 'state', check that this is the case.
|
||||||
Field(4, colRef=19),
|
Field(13, colRef=19),
|
||||||
Field(1, colRef=20),
|
Field(4, colRef=20),
|
||||||
Field(2, colRef=22),
|
Field(5, colRef=22),
|
||||||
Field(3, colRef=23),
|
Field(6, colRef=23),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
|
|
||||||
@ -830,27 +832,27 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=2, fields=[
|
Section(2, parentKey="record", tableRef=2, fields=[
|
||||||
Field(1, colRef=14),
|
Field(5, colRef=14),
|
||||||
Field(2, colRef=15),
|
Field(6, colRef=15),
|
||||||
Field(3, colRef=17),
|
Field(7, colRef=17),
|
||||||
Field(4, colRef=18),
|
Field(8, colRef=18),
|
||||||
])
|
])
|
||||||
]), View(2, sections=[
|
]), View(2, sections=[
|
||||||
Section(2, parentKey="record", tableRef=3, fields=[
|
Section(4, parentKey="record", tableRef=3, fields=[
|
||||||
Field(5, colRef=20),
|
Field(11, colRef=20),
|
||||||
Field(6, colRef=21),
|
Field(12, colRef=21),
|
||||||
]),
|
]),
|
||||||
Section(3, parentKey="record", tableRef=2, fields=[
|
Section(5, parentKey="record", tableRef=2, fields=[
|
||||||
Field(7, colRef=14),
|
Field(13, colRef=14),
|
||||||
Field(8, colRef=15),
|
Field(14, colRef=15),
|
||||||
Field(9, colRef=17),
|
Field(15, colRef=17),
|
||||||
Field(10, colRef=18),
|
Field(16, colRef=18),
|
||||||
]),
|
]),
|
||||||
Section(4, parentKey="record", tableRef=4, fields=[
|
Section(7, parentKey="record", tableRef=4, fields=[
|
||||||
Field(11, colRef=22),
|
Field(20, colRef=22),
|
||||||
Field(12, colRef=24),
|
Field(21, colRef=24),
|
||||||
Field(13, colRef=25),
|
Field(22, colRef=25),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
|
|
||||||
@ -869,11 +871,11 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertViews([View(1, sections=[
|
self.assertViews([View(1, sections=[
|
||||||
Section(1, parentKey="record", tableRef=2, fields=[
|
Section(2, parentKey="record", tableRef=2, fields=[
|
||||||
Field(1, colRef=14),
|
Field(5, colRef=14),
|
||||||
Field(2, colRef=15),
|
Field(6, colRef=15),
|
||||||
Field(3, colRef=17),
|
Field(7, colRef=17),
|
||||||
Field(4, colRef=18),
|
Field(8, colRef=18),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
|
|
||||||
@ -885,10 +887,10 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
self.load_sample(self.sample)
|
self.load_sample(self.sample)
|
||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
||||||
self.apply_user_action(["UpdateRecord", "_grist_Views_section", 1,
|
self.apply_user_action(["UpdateRecord", "_grist_Views_section", 2,
|
||||||
{"sortColRefs": "[15,14,-17]"}])
|
{"sortColRefs": "[15,14,-17]"}])
|
||||||
|
|
||||||
# We should have a single summary table, and a single section referring to it.
|
# We should have a single summary table, and a single (non-raw) section referring to it.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
||||||
@ -901,11 +903,12 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views_section', cols="subset", data=[
|
self.assertTableData('_grist_Views_section', cols="subset", data=[
|
||||||
["id", "tableRef", "sortColRefs"],
|
["id", "tableRef", "sortColRefs"],
|
||||||
[1, 2, "[15,14,-17]"],
|
[1, 2, ""], # This is the raw section.
|
||||||
|
[2, 2, "[15,14,-17]"],
|
||||||
])
|
])
|
||||||
|
|
||||||
# Now change the group-by to just one of the columns ('state')
|
# Now change the group-by to just one of the columns ('state')
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 1, [12]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [12]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #2 is gone at this point, since it's unused.
|
# Note that Table #2 is gone at this point, since it's unused.
|
||||||
@ -919,7 +922,8 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# Verify that sortColRefs refers to new columns.
|
# Verify that sortColRefs refers to new columns.
|
||||||
self.assertTableData('_grist_Views_section', cols="subset", data=[
|
self.assertTableData('_grist_Views_section', cols="subset", data=[
|
||||||
["id", "tableRef", "sortColRefs"],
|
["id", "tableRef", "sortColRefs"],
|
||||||
[1, 3, "[19,-21]"],
|
[2, 3, "[19,-21]"],
|
||||||
|
[3, 3, ""], # This is the raw section.
|
||||||
])
|
])
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
@ -953,8 +957,10 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views_section', cols="subset", data=[
|
self.assertTableData('_grist_Views_section', cols="subset", data=[
|
||||||
["id", "parentId", "tableRef"],
|
["id", "parentId", "tableRef"],
|
||||||
[1, 1, 2],
|
[1, 0, 2],
|
||||||
[2, 2, 3],
|
[2, 1, 2],
|
||||||
|
[3, 0, 3],
|
||||||
|
[4, 2, 3],
|
||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views_section_field', cols="subset", data=[
|
self.assertTableData('_grist_Views_section_field', cols="subset", data=[
|
||||||
["id", "parentId", "colRef"],
|
["id", "parentId", "colRef"],
|
||||||
@ -962,13 +968,20 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[2, 1, 15],
|
[2, 1, 15],
|
||||||
[3, 1, 17],
|
[3, 1, 17],
|
||||||
[4, 1, 18],
|
[4, 1, 18],
|
||||||
[7, 1, 22],
|
[13, 1, 22],
|
||||||
[5, 2, 20],
|
[5, 2, 14],
|
||||||
[6, 2, 21],
|
[6, 2, 15],
|
||||||
|
[7, 2, 17],
|
||||||
|
[8, 2, 18],
|
||||||
|
[14, 2, 22],
|
||||||
|
[9, 3, 20],
|
||||||
|
[10, 3, 21],
|
||||||
|
[11, 4, 20],
|
||||||
|
[12, 4, 21],
|
||||||
], sort=lambda r: (r.parentId, r.id))
|
], sort=lambda r: (r.parentId, r.id))
|
||||||
|
|
||||||
# Now save one section as a separate table, i.e. "detach" it from its source.
|
# Now save one section as a separate table, i.e. "detach" it from its source.
|
||||||
self.apply_user_action(["DetachSummaryViewSection", 1])
|
self.apply_user_action(["DetachSummaryViewSection", 2])
|
||||||
|
|
||||||
# Check the table and columns for all the summary tables.
|
# Check the table and columns for all the summary tables.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
@ -992,25 +1005,25 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# We should now have two sections for table 2 (the one with two group-by fields).
|
# We should now have two sections for table 2 (the one with two group-by fields).
|
||||||
self.assertTableData('_grist_Views_section', cols="subset", rows=lambda r: r.parentId, data=[
|
self.assertTableData('_grist_Views_section', cols="subset", rows=lambda r: r.parentId, data=[
|
||||||
["id", "parentId", "tableRef"],
|
["id", "parentId", "tableRef"],
|
||||||
[1, 1, 4],
|
[2, 1, 4],
|
||||||
[2, 2, 3],
|
[4, 2, 3],
|
||||||
[3, 3, 4],
|
[5, 3, 4],
|
||||||
])
|
])
|
||||||
self.assertTableData(
|
self.assertTableData(
|
||||||
'_grist_Views_section_field', cols="subset", rows=lambda r: r.parentId.parentId, data=[
|
'_grist_Views_section_field', cols="subset", rows=lambda r: r.parentId.parentId, data=[
|
||||||
["id", "parentId", "colRef"],
|
["id", "parentId", "colRef"],
|
||||||
[1, 1, 24],
|
[5, 2, 24],
|
||||||
[2, 1, 25],
|
[6, 2, 25],
|
||||||
[3, 1, 26],
|
[7, 2, 26],
|
||||||
[4, 1, 27],
|
[8, 2, 27],
|
||||||
[7, 1, 28],
|
[14, 2, 28],
|
||||||
[5, 2, 20],
|
[11, 4, 20],
|
||||||
[6, 2, 21],
|
[12, 4, 21],
|
||||||
[8, 3, 24],
|
[15, 5, 24],
|
||||||
[9, 3, 25],
|
[16, 5, 25],
|
||||||
[10, 3, 26],
|
[17, 5, 26],
|
||||||
[11, 3, 27],
|
[18, 5, 27],
|
||||||
[12, 3, 28],
|
[19, 5, 28],
|
||||||
], sort=lambda r: (r.parentId, r.id))
|
], sort=lambda r: (r.parentId, r.id))
|
||||||
|
|
||||||
# Check that the data is as we expect.
|
# Check that the data is as we expect.
|
||||||
@ -1039,7 +1052,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# Add a summary table and detach it. Then add a summary table of that table.
|
# Add a summary table and detach it. Then add a summary table of that table.
|
||||||
self.load_sample(self.sample)
|
self.load_sample(self.sample)
|
||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
||||||
self.apply_user_action(["DetachSummaryViewSection", 1])
|
self.apply_user_action(["DetachSummaryViewSection", 2])
|
||||||
|
|
||||||
# Create a summary of the detached table (tableRef 3) by state (colRef 21).
|
# Create a summary of the detached table (tableRef 3) by state (colRef 21).
|
||||||
self.apply_user_action(["CreateViewSection", 3, 0, "record", [21], None])
|
self.apply_user_action(["CreateViewSection", 3, 0, "record", [21], None])
|
||||||
|
@ -310,7 +310,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.assertTableData('GristSummary_6_Source2', data=summary_data)
|
self.assertTableData('GristSummary_6_Source2', data=summary_data)
|
||||||
|
|
||||||
# Verify that "DetachSummaryViewSection" useraction works correctly.
|
# Verify that "DetachSummaryViewSection" useraction works correctly.
|
||||||
self.apply_user_action(["DetachSummaryViewSection", 2])
|
self.apply_user_action(["DetachSummaryViewSection", 4])
|
||||||
|
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table, summary_table1, summary_table3, summary_table4,
|
self.starting_table, summary_table1, summary_table3, summary_table4,
|
||||||
|
@ -100,15 +100,15 @@ class TestTableActions(test_engine.EngineTestCase):
|
|||||||
Field(14, colRef=3),
|
Field(14, colRef=3),
|
||||||
Field(15, colRef=4),
|
Field(15, colRef=4),
|
||||||
]),
|
]),
|
||||||
Section(6, parentKey="record", tableRef=3, fields=[
|
Section(7, parentKey="record", tableRef=3, fields=[
|
||||||
Field(16, colRef=9),
|
Field(19, colRef=9),
|
||||||
Field(17, colRef=11),
|
Field(20, colRef=11),
|
||||||
Field(18, colRef=12),
|
Field(21, colRef=12),
|
||||||
]),
|
]),
|
||||||
Section(7, parentKey="record", tableRef=2, fields=[
|
Section(8, parentKey="record", tableRef=2, fields=[
|
||||||
Field(19, colRef=6),
|
Field(22, colRef=6),
|
||||||
Field(20, colRef=7),
|
Field(23, colRef=7),
|
||||||
Field(21, colRef=8),
|
Field(24, colRef=8),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
@ -300,9 +300,9 @@ class TestTableActions(test_engine.EngineTestCase):
|
|||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
View(3, sections=[
|
View(3, sections=[
|
||||||
Section(7, parentKey="record", tableRef=2, fields=[
|
Section(8, parentKey="record", tableRef=2, fields=[
|
||||||
Field(19, colRef=6),
|
Field(22, colRef=6),
|
||||||
Field(21, colRef=8),
|
Field(24, colRef=8),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
|
@ -172,9 +172,9 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
Section(2, parentKey="record", tableRef=1, fields=[
|
Section(2, parentKey="record", tableRef=1, fields=[
|
||||||
Field(2, colRef=21),
|
Field(2, colRef=21),
|
||||||
]),
|
]),
|
||||||
Section(3, parentKey="record", tableRef=2, fields=[
|
Section(4, parentKey="record", tableRef=2, fields=[
|
||||||
Field(3, colRef=22),
|
Field(5, colRef=22),
|
||||||
Field(4, colRef=24),
|
Field(6, colRef=24),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.assertTables([self.starting_table, summary_table])
|
self.assertTables([self.starting_table, summary_table])
|
||||||
@ -255,8 +255,8 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
Column(35, "count", "Int", isFormula=True, formula="len($group)", summarySourceCol=0),
|
Column(35, "count", "Int", isFormula=True, formula="len($group)", summarySourceCol=0),
|
||||||
])
|
])
|
||||||
self.assertTables([self.starting_table, new_table, new_table2, new_table3, summary_table])
|
self.assertTables([self.starting_table, new_table, new_table2, new_table3, summary_table])
|
||||||
new_view.sections.append(Section(6, parentKey="record", tableRef=5, fields=[
|
new_view.sections.append(Section(7, parentKey="record", tableRef=5, fields=[
|
||||||
Field(16, colRef=35)
|
Field(17, colRef=35)
|
||||||
]))
|
]))
|
||||||
self.assertViews([new_view])
|
self.assertViews([new_view])
|
||||||
|
|
||||||
@ -315,21 +315,21 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
Field(8, colRef=3),
|
Field(8, colRef=3),
|
||||||
Field(9, colRef=4),
|
Field(9, colRef=4),
|
||||||
]),
|
]),
|
||||||
Section(4, parentKey="record", tableRef=2, fields=[
|
Section(5, parentKey="record", tableRef=2, fields=[
|
||||||
Field(10, colRef=5),
|
Field(13, colRef=5),
|
||||||
Field(11, colRef=7),
|
Field(14, colRef=7),
|
||||||
Field(12, colRef=8),
|
Field(15, colRef=8),
|
||||||
]),
|
]),
|
||||||
Section(7, parentKey='record', tableRef=3, fields=[
|
Section(8, parentKey='record', tableRef=3, fields=[
|
||||||
Field(18, colRef=10),
|
Field(21, colRef=10),
|
||||||
Field(19, colRef=11),
|
Field(22, colRef=11),
|
||||||
Field(20, colRef=12),
|
Field(23, colRef=12),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
View(3, sections=[
|
View(3, sections=[
|
||||||
Section(5, parentKey="chart", tableRef=1, fields=[
|
Section(6, parentKey="chart", tableRef=1, fields=[
|
||||||
Field(13, colRef=2),
|
Field(16, colRef=2),
|
||||||
Field(14, colRef=3),
|
Field(17, colRef=3),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
@ -469,8 +469,8 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
||||||
[1, 'Z', 1, 2],
|
[1, 'Z', 1, 2],
|
||||||
[2, 'GristSummary_1_Z', 0, 0],
|
[2, 'GristSummary_1_Z', 0, 4],
|
||||||
[3, 'Table1', 0, 6],
|
[3, 'Table1', 0, 7],
|
||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views', cols="subset", data=[
|
self.assertTableData('_grist_Views', cols="subset", data=[
|
||||||
['id', 'name'],
|
['id', 'name'],
|
||||||
@ -486,9 +486,9 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
||||||
[1, 'Z', 1, 2],
|
[1, 'Z', 1, 2],
|
||||||
[2, 'GristSummary_1_Z', 0, 0],
|
[2, 'GristSummary_1_Z', 0, 4],
|
||||||
[3, 'Table1', 0, 6],
|
[3, 'Table1', 0, 7],
|
||||||
[4, 'Stations', 4, 9],
|
[4, 'Stations', 4, 10],
|
||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views', cols="subset", data=[
|
self.assertTableData('_grist_Views', cols="subset", data=[
|
||||||
['id', 'name'],
|
['id', 'name'],
|
||||||
@ -546,27 +546,27 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
Field(8, colRef=3),
|
Field(8, colRef=3),
|
||||||
Field(9, colRef=4),
|
Field(9, colRef=4),
|
||||||
]),
|
]),
|
||||||
Section(4, parentKey="record", tableRef=2, fields=[
|
Section(5, parentKey="record", tableRef=2, fields=[
|
||||||
Field(10, colRef=5),
|
Field(13, colRef=5),
|
||||||
Field(11, colRef=7),
|
Field(14, colRef=7),
|
||||||
Field(12, colRef=8),
|
Field(15, colRef=8),
|
||||||
]),
|
]),
|
||||||
Section(7, parentKey='record', tableRef=3, fields=[
|
Section(8, parentKey='record', tableRef=3, fields=[
|
||||||
Field(18, colRef=10),
|
Field(21, colRef=10),
|
||||||
Field(19, colRef=11),
|
Field(22, colRef=11),
|
||||||
Field(20, colRef=12),
|
Field(23, colRef=12),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
View(3, sections=[
|
View(3, sections=[
|
||||||
Section(5, parentKey="chart", tableRef=1, fields=[
|
Section(6, parentKey="chart", tableRef=1, fields=[
|
||||||
Field(13, colRef=2),
|
Field(16, colRef=2),
|
||||||
Field(14, colRef=3),
|
Field(17, colRef=3),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
# Remove a couple of sections. Ensure their fields get removed.
|
# Remove a couple of sections. Ensure their fields get removed.
|
||||||
self.apply_user_action(['BulkRemoveRecord', '_grist_Views_section', [4, 7]])
|
self.apply_user_action(['BulkRemoveRecord', '_grist_Views_section', [5, 8]])
|
||||||
|
|
||||||
self.assertViews([
|
self.assertViews([
|
||||||
View(1, sections=[
|
View(1, sections=[
|
||||||
@ -584,9 +584,9 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
View(3, sections=[
|
View(3, sections=[
|
||||||
Section(5, parentKey="chart", tableRef=1, fields=[
|
Section(6, parentKey="chart", tableRef=1, fields=[
|
||||||
Field(13, colRef=2),
|
Field(16, colRef=2),
|
||||||
Field(14, colRef=3),
|
Field(17, colRef=3),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
@ -607,13 +607,13 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
orig_method()
|
orig_method()
|
||||||
self.engine.assert_schema_consistent = types.MethodType(override, self.engine)
|
self.engine.assert_schema_consistent = types.MethodType(override, self.engine)
|
||||||
|
|
||||||
# Do a non-sschema action to ensure it doesn't get called.
|
# Do a non-schema action to ensure it doesn't get called.
|
||||||
self.apply_user_action(['UpdateRecord', '_grist_Views', 2, {'name': 'A'}])
|
self.apply_user_action(['UpdateRecord', '_grist_Views', 2, {'name': 'A'}])
|
||||||
self.assertEqual(count_calls[0], 0)
|
self.assertEqual(count_calls[0], 0)
|
||||||
|
|
||||||
# Do a schema action to ensure it gets called: this causes a table rename.
|
# Do a schema action to ensure it gets called: this causes a table rename.
|
||||||
# 7 is id of raw view section for the Tabl1 table
|
# 7 is id of raw view section for the Tabl1 table
|
||||||
self.apply_user_action(['UpdateRecord', '_grist_Views_section', 6, {'title': 'C'}])
|
self.apply_user_action(['UpdateRecord', '_grist_Views_section', 7, {'title': 'C'}])
|
||||||
self.assertEqual(count_calls[0], 1)
|
self.assertEqual(count_calls[0], 1)
|
||||||
|
|
||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
|
@ -455,10 +455,17 @@ class UserActions(object):
|
|||||||
if (
|
if (
|
||||||
table_id == "_grist_Views_section"
|
table_id == "_grist_Views_section"
|
||||||
and any(rec.isRaw for i, rec in self._bulk_action_iter(table_id, row_ids))
|
and any(rec.isRaw for i, rec in self._bulk_action_iter(table_id, row_ids))
|
||||||
# Only these fields are allowed to be modified
|
|
||||||
and not set(column_values) <= {"title", "options", "sortColRefs"}
|
|
||||||
):
|
):
|
||||||
raise ValueError("Cannot modify raw view section")
|
allowed_fields = {"title", "options", "sortColRefs"}
|
||||||
|
has_summary_section = any(rec.tableRef.summarySourceTable
|
||||||
|
for i, rec in self._bulk_action_iter(table_id, row_ids))
|
||||||
|
if has_summary_section:
|
||||||
|
# When a group-by column is removed from a summary source table, the source table reference
|
||||||
|
# changes; we pre-emptively allow changes to tableRef here to avoid blocking such actions.
|
||||||
|
allowed_fields.add("tableRef")
|
||||||
|
|
||||||
|
if not set(column_values) <= allowed_fields:
|
||||||
|
raise ValueError("Cannot modify raw view section")
|
||||||
|
|
||||||
if (
|
if (
|
||||||
table_id == "_grist_Views_section_field"
|
table_id == "_grist_Views_section_field"
|
||||||
@ -1734,12 +1741,12 @@ class UserActions(object):
|
|||||||
|
|
||||||
if raw_section:
|
if raw_section:
|
||||||
# Create raw view section
|
# Create raw view section
|
||||||
raw_section = self._create_plain_view_section(
|
raw_section = self.create_plain_view_section(
|
||||||
result["id"],
|
result["id"],
|
||||||
table_id,
|
table_id,
|
||||||
self._docmodel.view_sections,
|
self._docmodel.view_sections,
|
||||||
"record",
|
"record",
|
||||||
table_title
|
table_title if not summarySourceTableRef else ""
|
||||||
)
|
)
|
||||||
|
|
||||||
if primary_view or raw_section:
|
if primary_view or raw_section:
|
||||||
@ -1800,7 +1807,7 @@ class UserActions(object):
|
|||||||
if groupby_colrefs is not None:
|
if groupby_colrefs is not None:
|
||||||
section = self._summary.create_new_summary_section(table, groupby_cols, view, section_type)
|
section = self._summary.create_new_summary_section(table, groupby_cols, view, section_type)
|
||||||
else:
|
else:
|
||||||
section = self._create_plain_view_section(
|
section = self.create_plain_view_section(
|
||||||
table.id,
|
table.id,
|
||||||
table.tableId,
|
table.tableId,
|
||||||
view.viewSections,
|
view.viewSections,
|
||||||
@ -1813,7 +1820,7 @@ class UserActions(object):
|
|||||||
'sectionRef': section.id
|
'sectionRef': section.id
|
||||||
}
|
}
|
||||||
|
|
||||||
def _create_plain_view_section(self, tableRef, tableId, view_sections, section_type, title):
|
def create_plain_view_section(self, tableRef, tableId, view_sections, section_type, title):
|
||||||
# If title is the same as tableId leave it empty
|
# If title is the same as tableId leave it empty
|
||||||
if title == tableId:
|
if title == tableId:
|
||||||
title = ''
|
title = ''
|
||||||
|
@ -89,6 +89,7 @@
|
|||||||
--icon-PinBig: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTExLjgyOTcyODEsLTcuNjAyODA3MjdlLTEzIEw0LjE5Mjk3NDkxLC03LjU3NjE2MTkyZS0xMyBDMy42MjcyODk0OCwtNy41MzE3NTNlLTEzIDMuMjAzMDI1NDEsMC40MTAyNTY0MSAzLjIwMzAyNTQxLDAuOTU3MjY0OTU3IEMzLjIwMzAyNTQxLDEuNTA0MjczNSAzLjYyNzI4OTQ4LDEuOTE0NTI5OTEgNC4xOTI5NzQ5MSwxLjkxNDUyOTkxIEw1LjA0MTUwMzA0LDEuOTE0NTI5OTEgTDIuODQ5NDcyMDIsOS4wOTQwMTcwOSBMMS40MzUyNTg0Niw5LjA5NDAxNzA5IEMwLjg2OTU3MzAzNiw5LjA5NDAxNzA5IDAuNDQ1MzA4OTY3LDkuNTA0MjczNSAwLjQ0NTMwODk2NywxMC4wNTEyODIxIEMwLjQ0NTMwODk2NywxMC41OTgyOTA2IDAuODY5NTczMDM2LDExLjAwODU0NyAxLjQzNTI1ODQ2LDExLjAwODU0NyBMMy41NTY1Nzg4LDExLjAwODU0NyBMNi45NTA2OTEzNSwxMS4wMDg1NDcgTDcuMDIxNDAyMDMsMTYgTDkuMDAxMzAxMDIsMTYgTDkuMDAxMzAxMDIsMTAuOTQwMTcwOSBMMTQuNjU4MTU1MywxMC45NDAxNzA5IEMxNS4zNjUyNjIxLDEwLjk0MDE3MDkgMTUuNjQ4MTA0OCwxMC4yNTY0MTAzIDE1LjY0ODEwNDgsOS45ODI5MDU5OCBDMTUuNjQ4MTA0OCw5LjQzNTg5NzQ0IDE1LjIyMzg0MDcsOS4wMjU2NDEwMyAxNC42NTgxNTUzLDkuMDI1NjQxMDMgTDEzLjI0Mzk0MTcsOS4wMjU2NDEwMyBMMTEuMTIyNjIxNCwxLjkxNDUyOTkxIEwxMS45NzExNDk1LDEuOTE0NTI5OTEgQzEyLjgxOTY3NzYsMS45MTQ1Mjk5MSAxMi45NjEwOTksMS4yMzA3NjkyMyAxMi45NjEwOTksMC45NTcyNjQ5NTcgQzEyLjg5MDM4ODMsMC40Nzg2MzI0NzkgMTIuMzk1NDEzNiwtNy42NjQ5Nzk3NmUtMTMgMTEuODI5NzI4MSwtNy42MDI4MDcyN2UtMTMgWiBNMTEuMDUxOTEwNyw5LjA5NDAxNzA5IEw0Ljk3MDc5MjM3LDkuMDk0MDE3MDkgTDcuMDkyMTEyNzEsMS45ODI5MDU5OCBMOC45MzA1OTAzNCwxLjk4MjkwNTk4IEwxMS4wNTE5MTA3LDkuMDk0MDE3MDkgWiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+');
|
--icon-PinBig: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTExLjgyOTcyODEsLTcuNjAyODA3MjdlLTEzIEw0LjE5Mjk3NDkxLC03LjU3NjE2MTkyZS0xMyBDMy42MjcyODk0OCwtNy41MzE3NTNlLTEzIDMuMjAzMDI1NDEsMC40MTAyNTY0MSAzLjIwMzAyNTQxLDAuOTU3MjY0OTU3IEMzLjIwMzAyNTQxLDEuNTA0MjczNSAzLjYyNzI4OTQ4LDEuOTE0NTI5OTEgNC4xOTI5NzQ5MSwxLjkxNDUyOTkxIEw1LjA0MTUwMzA0LDEuOTE0NTI5OTEgTDIuODQ5NDcyMDIsOS4wOTQwMTcwOSBMMS40MzUyNTg0Niw5LjA5NDAxNzA5IEMwLjg2OTU3MzAzNiw5LjA5NDAxNzA5IDAuNDQ1MzA4OTY3LDkuNTA0MjczNSAwLjQ0NTMwODk2NywxMC4wNTEyODIxIEMwLjQ0NTMwODk2NywxMC41OTgyOTA2IDAuODY5NTczMDM2LDExLjAwODU0NyAxLjQzNTI1ODQ2LDExLjAwODU0NyBMMy41NTY1Nzg4LDExLjAwODU0NyBMNi45NTA2OTEzNSwxMS4wMDg1NDcgTDcuMDIxNDAyMDMsMTYgTDkuMDAxMzAxMDIsMTYgTDkuMDAxMzAxMDIsMTAuOTQwMTcwOSBMMTQuNjU4MTU1MywxMC45NDAxNzA5IEMxNS4zNjUyNjIxLDEwLjk0MDE3MDkgMTUuNjQ4MTA0OCwxMC4yNTY0MTAzIDE1LjY0ODEwNDgsOS45ODI5MDU5OCBDMTUuNjQ4MTA0OCw5LjQzNTg5NzQ0IDE1LjIyMzg0MDcsOS4wMjU2NDEwMyAxNC42NTgxNTUzLDkuMDI1NjQxMDMgTDEzLjI0Mzk0MTcsOS4wMjU2NDEwMyBMMTEuMTIyNjIxNCwxLjkxNDUyOTkxIEwxMS45NzExNDk1LDEuOTE0NTI5OTEgQzEyLjgxOTY3NzYsMS45MTQ1Mjk5MSAxMi45NjEwOTksMS4yMzA3NjkyMyAxMi45NjEwOTksMC45NTcyNjQ5NTcgQzEyLjg5MDM4ODMsMC40Nzg2MzI0NzkgMTIuMzk1NDEzNiwtNy42NjQ5Nzk3NmUtMTMgMTEuODI5NzI4MSwtNy42MDI4MDcyN2UtMTMgWiBNMTEuMDUxOTEwNyw5LjA5NDAxNzA5IEw0Ljk3MDc5MjM3LDkuMDk0MDE3MDkgTDcuMDkyMTEyNzEsMS45ODI5MDU5OCBMOC45MzA1OTAzNCwxLjk4MjkwNTk4IEwxMS4wNTE5MTA3LDkuMDk0MDE3MDkgWiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+');
|
||||||
--icon-PinSmall: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTcuNSwxMSBMMi41LDExIEMyLjIyMzg1NzYzLDExIDIsMTAuNzc2MTQyNCAyLDEwLjUgQzIsMTAuMjIzODU3NiAyLjIyMzg1NzYzLDEwIDIuNSwxMCBMNC4yNSwxMCBMNS43NSw0IEw0LjUsNCBDNC4yMjM4NTc2Myw0IDQsMy43NzYxNDIzNyA0LDMuNSBDNCwzLjIyMzg1NzYzIDQuMjIzODU3NjMsMyA0LjUsMyBMMTEuNSwzIEMxMS43NzYxNDI0LDMgMTIsMy4yMjM4NTc2MyAxMiwzLjUgQzEyLDMuNzc2MTQyMzcgMTEuNzc2MTQyNCw0IDExLjUsNCBMMTAuMjUsNCBMMTEuNzUsMTAgTDEzLjUsMTAgQzEzLjc3NjE0MjQsMTAgMTQsMTAuMjIzODU3NiAxNCwxMC41IEMxNCwxMC43NzYxNDI0IDEzLjc3NjE0MjQsMTEgMTMuNSwxMSBMOC41LDExIEw4LjUsMTQgTDcuNSwxNCBMNy41LDExIFogTTUuMjgwNzc2NDEsMTAgTDEwLjcxOTIyMzYsMTAgTDkuMjE5MjIzNTksNCBMNi43ODA3NzY0MSw0IEw1LjI4MDc3NjQxLDEwIFoiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');
|
--icon-PinSmall: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTcuNSwxMSBMMi41LDExIEMyLjIyMzg1NzYzLDExIDIsMTAuNzc2MTQyNCAyLDEwLjUgQzIsMTAuMjIzODU3NiAyLjIyMzg1NzYzLDEwIDIuNSwxMCBMNC4yNSwxMCBMNS43NSw0IEw0LjUsNCBDNC4yMjM4NTc2Myw0IDQsMy43NzYxNDIzNyA0LDMuNSBDNCwzLjIyMzg1NzYzIDQuMjIzODU3NjMsMyA0LjUsMyBMMTEuNSwzIEMxMS43NzYxNDI0LDMgMTIsMy4yMjM4NTc2MyAxMiwzLjUgQzEyLDMuNzc2MTQyMzcgMTEuNzc2MTQyNCw0IDExLjUsNCBMMTAuMjUsNCBMMTEuNzUsMTAgTDEzLjUsMTAgQzEzLjc3NjE0MjQsMTAgMTQsMTAuMjIzODU3NiAxNCwxMC41IEMxNCwxMC43NzYxNDI0IDEzLjc3NjE0MjQsMTEgMTMuNSwxMSBMOC41LDExIEw4LjUsMTQgTDcuNSwxNCBMNy41LDExIFogTTUuMjgwNzc2NDEsMTAgTDEwLjcxOTIyMzYsMTAgTDkuMjE5MjIzNTksNCBMNi43ODA3NzY0MSw0IEw1LjI4MDc3NjQxLDEwIFoiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');
|
||||||
--icon-Pivot: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTMsMSBMMTMsMSBDMTQuMTA0NTY5NSwxIDE1LDEuODk1NDMwNSAxNSwzIEwxNSwxMyBDMTUsMTQuMTA0NTY5NSAxNC4xMDQ1Njk1LDE1IDEzLDE1IEwzLDE1IEMxLjg5NTQzMDUsMTUgMSwxNC4xMDQ1Njk1IDEsMTMgTDEsMyBDMSwxLjg5NTQzMDUgMS44OTU0MzA1LDEgMywxIFogTTUuMzc1LDQuNSBMNS4zNzUsNC43ODU0NjM0MSBMNy42MzQ2NTAxLDguMDIyNzA3MzIgTDUuMzc1LDExLjA5NDUxMjIgTDUuMzc1LDExLjUgTDEwLjYyNSwxMS41IEwxMC42MjUsMTAuMDMyODE3MSBMOS44MjY0OTkwMSwxMC43MjY0MTQ2IEw2LjkxOTczMTYxLDEwLjcyNjQxNDYgTDYuOTE5NzMxNjEsMTAuNDE2OTYzNCBMOC45MDI4MzMsNy42MTU4NTM2NiBMNi45MTk3MzE2MSw0Ljk5MDg1MzY2IEw5Ljc3NDMxMjEzLDQuOTg3MzUzNjYgTDEwLjYyNSw2LjA5NTMxNzA3IEwxMC42MjUsNC41IEw1LjM3NSw0LjUgWiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+');
|
--icon-Pivot: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTMsMSBMMTMsMSBDMTQuMTA0NTY5NSwxIDE1LDEuODk1NDMwNSAxNSwzIEwxNSwxMyBDMTUsMTQuMTA0NTY5NSAxNC4xMDQ1Njk1LDE1IDEzLDE1IEwzLDE1IEMxLjg5NTQzMDUsMTUgMSwxNC4xMDQ1Njk1IDEsMTMgTDEsMyBDMSwxLjg5NTQzMDUgMS44OTU0MzA1LDEgMywxIFogTTUuMzc1LDQuNSBMNS4zNzUsNC43ODU0NjM0MSBMNy42MzQ2NTAxLDguMDIyNzA3MzIgTDUuMzc1LDExLjA5NDUxMjIgTDUuMzc1LDExLjUgTDEwLjYyNSwxMS41IEwxMC42MjUsMTAuMDMyODE3MSBMOS44MjY0OTkwMSwxMC43MjY0MTQ2IEw2LjkxOTczMTYxLDEwLjcyNjQxNDYgTDYuOTE5NzMxNjEsMTAuNDE2OTYzNCBMOC45MDI4MzMsNy42MTU4NTM2NiBMNi45MTk3MzE2MSw0Ljk5MDg1MzY2IEw5Ljc3NDMxMjEzLDQuOTg3MzUzNjYgTDEwLjYyNSw2LjA5NTMxNzA3IEwxMC42MjUsNC41IEw1LjM3NSw0LjUgWiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+');
|
||||||
|
--icon-PivotLight: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cmVjdCBzdHJva2U9IiM5Nzk3OTciIHg9Ii41IiB5PSIuNSIgd2lkdGg9IjE1IiBoZWlnaHQ9IjE1IiByeD0iMiIvPjxwYXRoIGZpbGw9IiM5Nzk3OTciIGQ9Ik01LjM3NSA0LjVMMTAuNjI1IDQuNSAxMC42MjUgNi4wOTUzMTcwNyA5Ljc3NDMxMjEzIDQuOTg3MzUzNjYgNi45MTk3MzE2MSA0Ljk5MDg1MzY2IDguOTAyODMzIDcuNjE1ODUzNjYgNi45MTk3MzE2MSAxMC40MTY5NjM0IDYuOTE5NzMxNjEgMTAuNzI2NDE0NiA5LjgyNjQ5OTAxIDEwLjcyNjQxNDYgMTAuNjI1IDEwLjAzMjgxNzEgMTAuNjI1IDExLjUgNS4zNzUgMTEuNSA1LjM3NSAxMS4wOTQ1MTIyIDcuNjM0NjUwMSA4LjAyMjcwNzMyIDUuMzc1IDQuNzg1NDYzNDF6Ii8+PC9nPjwvc3ZnPg==');
|
||||||
--icon-Plus: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTguNSw3LjUgTDEzLDcuNSBDMTMuMjc2MTQyNCw3LjUgMTMuNSw3LjcyMzg1NzYzIDEzLjUsOCBDMTMuNSw4LjI3NjE0MjM3IDEzLjI3NjE0MjQsOC41IDEzLDguNSBMOC41LDguNSBMOC41LDEzIEM4LjUsMTMuMjc2MTQyNCA4LjI3NjE0MjM3LDEzLjUgOCwxMy41IEM3LjcyMzg1NzYzLDEzLjUgNy41LDEzLjI3NjE0MjQgNy41LDEzIEw3LjUsOC41IEwzLDguNSBDMi43MjM4NTc2Myw4LjUgMi41LDguMjc2MTQyMzcgMi41LDggQzIuNSw3LjcyMzg1NzYzIDIuNzIzODU3NjMsNy41IDMsNy41IEw3LjUsNy41IEw3LjUsMyBDNy41LDIuNzIzODU3NjMgNy43MjM4NTc2MywyLjUgOCwyLjUgQzguMjc2MTQyMzcsMi41IDguNSwyLjcyMzg1NzYzIDguNSwzIEw4LjUsNy41IFoiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');
|
--icon-Plus: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTguNSw3LjUgTDEzLDcuNSBDMTMuMjc2MTQyNCw3LjUgMTMuNSw3LjcyMzg1NzYzIDEzLjUsOCBDMTMuNSw4LjI3NjE0MjM3IDEzLjI3NjE0MjQsOC41IDEzLDguNSBMOC41LDguNSBMOC41LDEzIEM4LjUsMTMuMjc2MTQyNCA4LjI3NjE0MjM3LDEzLjUgOCwxMy41IEM3LjcyMzg1NzYzLDEzLjUgNy41LDEzLjI3NjE0MjQgNy41LDEzIEw3LjUsOC41IEwzLDguNSBDMi43MjM4NTc2Myw4LjUgMi41LDguMjc2MTQyMzcgMi41LDggQzIuNSw3LjcyMzg1NzYzIDIuNzIzODU3NjMsNy41IDMsNy41IEw3LjUsNy41IEw3LjUsMyBDNy41LDIuNzIzODU3NjMgNy43MjM4NTc2MywyLjUgOCwyLjUgQzguMjc2MTQyMzcsMi41IDguNSwyLjcyMzg1NzYzIDguNSwzIEw4LjUsNy41IFoiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');
|
||||||
--icon-Public: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwSDE2VjE2SDB6Ii8+PGcgc3Ryb2tlPSIjMTZCMzc4IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik05Ljc3NSAxMS4yOTNMNy4zMTIgMTAuNTkzQzcuMTIyMjE2NjEgMTAuNTM4OTUxMSA2Ljk4MTk3MzAyIDEwLjM3ODMzNyA2Ljk1NCAxMC4xODNMNi43NDcgOC43MjZDNy44MTQxMjAyNiA4LjIzODMwNjE1IDguNDk5MDAyMDkgNy4xNzMyODE3IDguNSA2TDguNSA0LjYyNkM4LjUyNTE5NzU2IDIuOTczMDAzMjUgNy4yNDI1MDU0NyAxLjU5NDE1MzM3IDUuNTkyIDEuNSA0Ljc4MDUzMjcgMS40NzUxMDMyIDMuOTkzNjIwMiAxLjc4MDE0ODI3IDMuNDEwOTUzMjMgMi4zNDU0Nzg0NiAyLjgyODI4NjI1IDIuOTEwODA4NjQgMi40OTk2MTgxNiAzLjY4ODE1MDk1IDIuNSA0LjVMMi41IDZDMi41MDA5OTc5MSA3LjE3MzI4MTcgMy4xODU4Nzk3NCA4LjIzODMwNjE1IDQuMjUzIDguNzI2TDQuMDQ2IDEwLjE3OUM0LjAxODAyNjk4IDEwLjM3NDMzNyAzLjg3Nzc4MzM5IDEwLjUzNDk1MTEgMy42ODggMTAuNTg5TDEuMjI1IDExLjI4OUMuNzk1OTk1Njg4IDExLjQxMTcwNzIuNTAwMTk4MjMgMTEuODAzNzkxOC41IDEyLjI1TC41IDE0LjUgMTAuNSAxNC41IDEwLjUgMTIuMjU0QzEwLjQ5OTgwMTggMTEuODA3NzkxOCAxMC4yMDQwMDQzIDExLjQxNTcwNzIgOS43NzUgMTEuMjkzek0xMi41IDE0LjVMMTUuNSAxNC41IDE1LjUgMTEuMjgxQzE1LjQ5OTk4NzkgMTAuODIyMzIwNiAxNS4xODc5MzExIDEwLjQyMjQ1OTEgMTQuNzQzIDEwLjMxMUwxMS44MjYgOS41ODJDMTEuNjI4NDcxIDkuNTMyNzA4NDEgMTEuNDgwNTUyNCA5LjM2ODU3NDEgMTEuNDUyIDkuMTY3TDExLjI0NyA3LjcyNkMxMi4zMTQxMjAzIDcuMjM4MzA2MTUgMTIuOTk5MDAyMSA2LjE3MzI4MTcgMTMgNUwxMyAzLjYyNkMxMy4wMjUxOTc2IDEuOTczMDAzMjUgMTEuNzQyNTA1NS41OTQxNTMzNjUgMTAuMDkyLjUgOS41MzQ0NjYxNC40ODI3MzcyNzIgOC45ODMxNjAzOS42MjEyNTYzMDYgOC41LjkiLz48L2c+PC9nPjwvc3ZnPg==');
|
--icon-Public: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwSDE2VjE2SDB6Ii8+PGcgc3Ryb2tlPSIjMTZCMzc4IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik05Ljc3NSAxMS4yOTNMNy4zMTIgMTAuNTkzQzcuMTIyMjE2NjEgMTAuNTM4OTUxMSA2Ljk4MTk3MzAyIDEwLjM3ODMzNyA2Ljk1NCAxMC4xODNMNi43NDcgOC43MjZDNy44MTQxMjAyNiA4LjIzODMwNjE1IDguNDk5MDAyMDkgNy4xNzMyODE3IDguNSA2TDguNSA0LjYyNkM4LjUyNTE5NzU2IDIuOTczMDAzMjUgNy4yNDI1MDU0NyAxLjU5NDE1MzM3IDUuNTkyIDEuNSA0Ljc4MDUzMjcgMS40NzUxMDMyIDMuOTkzNjIwMiAxLjc4MDE0ODI3IDMuNDEwOTUzMjMgMi4zNDU0Nzg0NiAyLjgyODI4NjI1IDIuOTEwODA4NjQgMi40OTk2MTgxNiAzLjY4ODE1MDk1IDIuNSA0LjVMMi41IDZDMi41MDA5OTc5MSA3LjE3MzI4MTcgMy4xODU4Nzk3NCA4LjIzODMwNjE1IDQuMjUzIDguNzI2TDQuMDQ2IDEwLjE3OUM0LjAxODAyNjk4IDEwLjM3NDMzNyAzLjg3Nzc4MzM5IDEwLjUzNDk1MTEgMy42ODggMTAuNTg5TDEuMjI1IDExLjI4OUMuNzk1OTk1Njg4IDExLjQxMTcwNzIuNTAwMTk4MjMgMTEuODAzNzkxOC41IDEyLjI1TC41IDE0LjUgMTAuNSAxNC41IDEwLjUgMTIuMjU0QzEwLjQ5OTgwMTggMTEuODA3NzkxOCAxMC4yMDQwMDQzIDExLjQxNTcwNzIgOS43NzUgMTEuMjkzek0xMi41IDE0LjVMMTUuNSAxNC41IDE1LjUgMTEuMjgxQzE1LjQ5OTk4NzkgMTAuODIyMzIwNiAxNS4xODc5MzExIDEwLjQyMjQ1OTEgMTQuNzQzIDEwLjMxMUwxMS44MjYgOS41ODJDMTEuNjI4NDcxIDkuNTMyNzA4NDEgMTEuNDgwNTUyNCA5LjM2ODU3NDEgMTEuNDUyIDkuMTY3TDExLjI0NyA3LjcyNkMxMi4zMTQxMjAzIDcuMjM4MzA2MTUgMTIuOTk5MDAyMSA2LjE3MzI4MTcgMTMgNUwxMyAzLjYyNkMxMy4wMjUxOTc2IDEuOTczMDAzMjUgMTEuNzQyNTA1NS41OTQxNTMzNjUgMTAuMDkyLjUgOS41MzQ0NjYxNC40ODI3MzcyNzIgOC45ODMxNjAzOS42MjEyNTYzMDYgOC41LjkiLz48L2c+PC9nPjwvc3ZnPg==');
|
||||||
--icon-PublicColor: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTQiIHdpZHRoPSIxNiI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwSDE2VjE2SDB6IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIC0xKSIvPjxnIG9wYWNpdHk9Ii43ODMiPjxwYXRoIGQ9Ik0gMTUuMjc1LDEwLjI5MyAxMy4wODcsOS42NjggQyAxMi43MjY0NzgsOS41NjQ5MTc4IDEyLjQ1MzkyLDkuMjY4ODEwNSAxMi4zODEsOC45MDEgTCAxMi4yNDcsOC4yMjYgQyAxMy4zMTQxMiw3LjczODMwNjEgMTMuOTk5MDAyLDYuNjczMjgxNyAxNCw1LjUgViA0LjEyNiBDIDE0LjAyNTE5OCwyLjQ3MzAwMzMgMTIuNzQyNTA2LDEuMDk0MTUzNCAxMS4wOTIsMSA5Ljg3OTM3MDksMC45NjM0MTA4MiA4Ljc2NDA2NTUsMS42NjA3NzI3IDguMjY2LDIuNzY3IDguNzQzMDQ3OCwzLjQ2MTI3ODUgOC45OTg5MTk4LDQuMjgzNjI0NyA5LDUuMTI2IFYgNi41IEMgOC45OTgyMDc3LDYuODYzNzcwNiA4Ljk0NjA0NTYsNy4yMjU1NDA0IDguODQ1LDcuNTc1IDkuMTA0MjMyNSw3Ljg0Njk0MjMgOS40MTIyMzk1LDguMDY3NzcxMSA5Ljc1Myw4LjIyNiBMIDkuNjE5LDguOSBDIDkuNTQ2MDc5Niw5LjI2NzgxMDUgOS4yNzM1MjE5LDkuNTYzOTE3OCA4LjkxMyw5LjY2NyBMIDguMDcsOS45MDggOS41NSwxMC4zMzEgYyAwLjg1Njk2NCwwLjI0NzU1NCAxLjQ0NzcwNiwxLjAzMDk5OSAxLjQ1LDEuOTIzIFYgMTQuNSBjIC0wLjAwMTcsMC4xNzA3MiAtMC4wMzI3OCwwLjMzOTg3MSAtMC4wOTIsMC41IEggMTUuNSBjIDAuMjc2MTQyLDAgMC41LC0wLjIyMzg1OCAwLjUsLTAuNSB2IC0zLjI0NiBjIC0xLjk4ZS00LC0wLjQ0NjIwOCAtMC4yOTU5OTYsLTAuODM4MjkzIC0wLjcyNSwtMC45NjEgeiIgZmlsbD0iI2U2YTExNyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMSkiLz48cGF0aCBkPSJNIDkuMjc1LDExLjI5MyA3LjA4NywxMC42NjggQyA2LjcyNjIwMjMsMTAuNTY0NzU0IDYuNDUzNTgzLDEwLjI2ODE5NCA2LjM4MSw5LjkgTCA2LjI0Nyw5LjIyNSBDIDcuMzEzNzkxNCw4LjczNzQ1NjkgNy45OTg2MTEyLDcuNjcyOTE5NSA4LDYuNSBWIDUuMTI2IEMgOC4wMjUxOTc2LDMuNDczMDAzMyA2Ljc0MjUwNTUsMi4wOTQxNTM0IDUuMDkyLDIgNC4yODA1MzI3LDEuOTc1MTAzMiAzLjQ5MzYyMDIsMi4yODAxNDgzIDIuOTEwOTUzMiwyLjg0NTQ3ODUgMi4zMjgyODYzLDMuNDEwODA4NiAxLjk5OTYxODIsNC4xODgxNTA5IDIsNSB2IDEuNSBjIDkuOTc5ZS00LDEuMTczMjgxNyAwLjY4NTg3OTcsMi4yMzgzMDYyIDEuNzUzLDIuNzI2IEwgMy42MTksOS45IEMgMy41NDYwOCwxMC4yNjc4MTEgMy4yNzM1MjE5LDEwLjU2MzkxOCAyLjkxMywxMC42NjcgTCAwLjcyNSwxMS4yOTIgQyAwLjI5NTYzOTI2LDExLjQxNDgwOSAtMi40ODE3NzE2ZS00LDExLjgwNzQyMSAwLDEyLjI1NCBWIDE0LjUgQyAwLDE0Ljc3NjE0MiAwLjIyMzg1NzYzLDE1IDAuNSwxNSBoIDkgQyA5Ljc3NjE0MjQsMTUgMTAsMTQuNzc2MTQyIDEwLDE0LjUgViAxMi4yNTQgQyA5Ljk5OTgwMTgsMTEuODA3NzkyIDkuNzA0MDA0MywxMS40MTU3MDcgOS4yNzUsMTEuMjkzIFoiIGZpbGw9IiNmZmYiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTEpIi8+PC9nPjwvZz48L3N2Zz4=');
|
--icon-PublicColor: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTQiIHdpZHRoPSIxNiI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwSDE2VjE2SDB6IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIC0xKSIvPjxnIG9wYWNpdHk9Ii43ODMiPjxwYXRoIGQ9Ik0gMTUuMjc1LDEwLjI5MyAxMy4wODcsOS42NjggQyAxMi43MjY0NzgsOS41NjQ5MTc4IDEyLjQ1MzkyLDkuMjY4ODEwNSAxMi4zODEsOC45MDEgTCAxMi4yNDcsOC4yMjYgQyAxMy4zMTQxMiw3LjczODMwNjEgMTMuOTk5MDAyLDYuNjczMjgxNyAxNCw1LjUgViA0LjEyNiBDIDE0LjAyNTE5OCwyLjQ3MzAwMzMgMTIuNzQyNTA2LDEuMDk0MTUzNCAxMS4wOTIsMSA5Ljg3OTM3MDksMC45NjM0MTA4MiA4Ljc2NDA2NTUsMS42NjA3NzI3IDguMjY2LDIuNzY3IDguNzQzMDQ3OCwzLjQ2MTI3ODUgOC45OTg5MTk4LDQuMjgzNjI0NyA5LDUuMTI2IFYgNi41IEMgOC45OTgyMDc3LDYuODYzNzcwNiA4Ljk0NjA0NTYsNy4yMjU1NDA0IDguODQ1LDcuNTc1IDkuMTA0MjMyNSw3Ljg0Njk0MjMgOS40MTIyMzk1LDguMDY3NzcxMSA5Ljc1Myw4LjIyNiBMIDkuNjE5LDguOSBDIDkuNTQ2MDc5Niw5LjI2NzgxMDUgOS4yNzM1MjE5LDkuNTYzOTE3OCA4LjkxMyw5LjY2NyBMIDguMDcsOS45MDggOS41NSwxMC4zMzEgYyAwLjg1Njk2NCwwLjI0NzU1NCAxLjQ0NzcwNiwxLjAzMDk5OSAxLjQ1LDEuOTIzIFYgMTQuNSBjIC0wLjAwMTcsMC4xNzA3MiAtMC4wMzI3OCwwLjMzOTg3MSAtMC4wOTIsMC41IEggMTUuNSBjIDAuMjc2MTQyLDAgMC41LC0wLjIyMzg1OCAwLjUsLTAuNSB2IC0zLjI0NiBjIC0xLjk4ZS00LC0wLjQ0NjIwOCAtMC4yOTU5OTYsLTAuODM4MjkzIC0wLjcyNSwtMC45NjEgeiIgZmlsbD0iI2U2YTExNyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtMSkiLz48cGF0aCBkPSJNIDkuMjc1LDExLjI5MyA3LjA4NywxMC42NjggQyA2LjcyNjIwMjMsMTAuNTY0NzU0IDYuNDUzNTgzLDEwLjI2ODE5NCA2LjM4MSw5LjkgTCA2LjI0Nyw5LjIyNSBDIDcuMzEzNzkxNCw4LjczNzQ1NjkgNy45OTg2MTEyLDcuNjcyOTE5NSA4LDYuNSBWIDUuMTI2IEMgOC4wMjUxOTc2LDMuNDczMDAzMyA2Ljc0MjUwNTUsMi4wOTQxNTM0IDUuMDkyLDIgNC4yODA1MzI3LDEuOTc1MTAzMiAzLjQ5MzYyMDIsMi4yODAxNDgzIDIuOTEwOTUzMiwyLjg0NTQ3ODUgMi4zMjgyODYzLDMuNDEwODA4NiAxLjk5OTYxODIsNC4xODgxNTA5IDIsNSB2IDEuNSBjIDkuOTc5ZS00LDEuMTczMjgxNyAwLjY4NTg3OTcsMi4yMzgzMDYyIDEuNzUzLDIuNzI2IEwgMy42MTksOS45IEMgMy41NDYwOCwxMC4yNjc4MTEgMy4yNzM1MjE5LDEwLjU2MzkxOCAyLjkxMywxMC42NjcgTCAwLjcyNSwxMS4yOTIgQyAwLjI5NTYzOTI2LDExLjQxNDgwOSAtMi40ODE3NzE2ZS00LDExLjgwNzQyMSAwLDEyLjI1NCBWIDE0LjUgQyAwLDE0Ljc3NjE0MiAwLjIyMzg1NzYzLDE1IDAuNSwxNSBoIDkgQyA5Ljc3NjE0MjQsMTUgMTAsMTQuNzc2MTQyIDEwLDE0LjUgViAxMi4yNTQgQyA5Ljk5OTgwMTgsMTEuODA3NzkyIDkuNzA0MDA0MywxMS40MTU3MDcgOS4yNzUsMTEuMjkzIFoiIGZpbGw9IiNmZmYiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTEpIi8+PC9nPjwvZz48L3N2Zz4=');
|
||||||
|
10
static/ui-icons/UI/PivotLight.svg
Normal file
10
static/ui-icons/UI/PivotLight.svg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
|
||||||
|
<title>Icons / UI / PivotLight</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<g id="Icons-/-UI-/-PivotLight" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<rect id="Rectangle" stroke="#979797" x="0.5" y="0.5" width="15" height="15" rx="2"></rect>
|
||||||
|
<polygon id="Path" fill="#979797" points="5.375 4.5 10.625 4.5 10.625 6.09531707 9.77431213 4.98735366 6.91973161 4.99085366 8.902833 7.61585366 6.91973161 10.4169634 6.91973161 10.7264146 9.82649901 10.7264146 10.625 10.0328171 10.625 11.5 5.375 11.5 5.375 11.0945122 7.6346501 8.02270732 5.375 4.78546341"></polygon>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 872 B |
BIN
test/fixtures/docs/Hello.grist
vendored
BIN
test/fixtures/docs/Hello.grist
vendored
Binary file not shown.
Loading…
Reference in New Issue
Block a user