mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Fix linking after a summary update
Summary: When linking table to a summary, the linking ended up broken after updating the summary group by columns. This diff fixes that issue. There were two issues: 1) some subscriptions were missing due to some .peek() calls instead of directly calling the observable. 2) the LinkingState instance was not being disposed. 3) the filterColValues was not updating after source data table has been loaded Test Plan: Include new test file. Reviewers: alexmojaki Reviewed By: alexmojaki Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D3358
This commit is contained in:
@@ -103,7 +103,16 @@ export class LinkingState extends Disposable {
|
||||
// TODO: This approach doesn't help cursor-linking (the other direction). If we have the
|
||||
// inverse of summary-table's 'group' column, we could implement both, and more efficiently.
|
||||
const isDirectSummary = srcSection.table().summarySourceTable() === tgtSection.table().getRowId();
|
||||
this.filterColValues = this.autoDispose(ko.computed(() => {
|
||||
const _filterColValues = ko.observable<FilterColValues>();
|
||||
this.filterColValues = this.autoDispose(ko.computed(() => _filterColValues()));
|
||||
|
||||
// source data table could still be loading (this could happen after changing the group by
|
||||
// columns of a linked summary table for instance), hence the below listeners.
|
||||
this.autoDispose(srcTableData.dataLoadedEmitter.addListener(_update));
|
||||
this.autoDispose(srcTableData.tableActionEmitter.addListener(_update));
|
||||
|
||||
_update();
|
||||
function _update() {
|
||||
const result: FilterColValues = {filters: {}, operations: {}};
|
||||
const srcRowId = srcSection.activeRowId();
|
||||
for (const c of srcSection.table().groupByColumns()) {
|
||||
@@ -119,8 +128,8 @@ export class LinkingState extends Disposable {
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
_filterColValues(result);
|
||||
}
|
||||
} else if (isSummaryOf(tgtSection.table(), srcSection.table())) {
|
||||
// TODO: We should move the cursor, but don't currently it for summaries. For that, we need a
|
||||
// column or map representing the inverse of summary table's "group" column.
|
||||
|
||||
@@ -22,7 +22,7 @@ import {arrayRepeat} from 'app/common/gutil';
|
||||
import {Sort} from 'app/common/SortSpec';
|
||||
import {ColumnsToMap, WidgetColumnMap} from 'app/plugin/CustomSectionAPI';
|
||||
import {ColumnToMapImpl} from 'app/client/models/ColumnToMap';
|
||||
import {Computed, Observable} from 'grainjs';
|
||||
import {Computed, Holder, Observable} from 'grainjs';
|
||||
import * as ko from 'knockout';
|
||||
import defaults = require('lodash/defaults');
|
||||
|
||||
@@ -118,6 +118,7 @@ export interface ViewSectionRec extends IRowModel<"_grist_Views_section"> {
|
||||
// Linking state maintains .filterFunc and .cursorPos observables which we use for
|
||||
// auto-scrolling and filtering.
|
||||
linkingState: ko.Computed<LinkingState | null>;
|
||||
_linkingState: Holder<LinkingState>; // Holder for the current value of linkingState
|
||||
|
||||
linkingFilter: ko.Computed<FilterColValues>;
|
||||
|
||||
@@ -473,15 +474,14 @@ export function createViewSectionRec(this: ViewSectionRec, docModel: DocModel):
|
||||
|
||||
this.activeRowId = ko.observable(null);
|
||||
|
||||
this._linkingState = Holder.create(this);
|
||||
this.linkingState = this.autoDispose(ko.pureComputed(() => {
|
||||
if (!this.linkSrcSection().getRowId()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const config = new LinkConfig(this);
|
||||
return new LinkingState(docModel, config);
|
||||
return LinkingState.create(this._linkingState, docModel, config);
|
||||
} catch (err) {
|
||||
console.warn(`Can't create LinkingState: ${err.message}`);
|
||||
// Dispose old LinkingState in case creating the new one failed.
|
||||
this._linkingState.dispose();
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -257,13 +257,14 @@ export class LinkConfig {
|
||||
// Use null for unset cols (rather than an empty ColumnRec) for easier comparisons below.
|
||||
const srcCol = this.srcCol?.getRowId() ? this.srcCol : null;
|
||||
const tgtCol = this.tgtCol?.getRowId() ? this.tgtCol : null;
|
||||
const srcTableId = (srcCol ? getReferencedTableId(srcCol.type.peek()) :
|
||||
this.srcSection.table.peek().primaryTableId.peek());
|
||||
const tgtTableId = (tgtCol ? getReferencedTableId(tgtCol.type.peek()) :
|
||||
this.tgtSection.table.peek().primaryTableId.peek());
|
||||
const srcTableId = (srcCol ? getReferencedTableId(srcCol.type()) :
|
||||
this.srcSection.table().primaryTableId());
|
||||
const tgtTableId = (tgtCol ? getReferencedTableId(tgtCol.type()) :
|
||||
this.tgtSection.table().primaryTableId());
|
||||
try {
|
||||
assert(!tgtCol || tgtCol.parentId.peek() === this.tgtSection.tableRef.peek(), "tgtCol belongs to wrong table");
|
||||
assert(!srcCol || srcCol.parentId.peek() === this.srcSection.tableRef.peek(), "srcCol belongs to wrong table");
|
||||
assert(Boolean(this.srcSection.getRowId()), "srcSection was disposed");
|
||||
assert(!tgtCol || tgtCol.parentId() === this.tgtSection.tableRef(), "tgtCol belongs to wrong table");
|
||||
assert(!srcCol || srcCol.parentId() === this.srcSection.tableRef(), "srcCol belongs to wrong table");
|
||||
assert(this.srcSection.getRowId() !== this.tgtSection.getRowId(), "srcSection links to itself");
|
||||
assert(tgtTableId, "tgtCol not a valid reference");
|
||||
assert(srcTableId, "srcCol not a valid reference");
|
||||
|
||||
Reference in New Issue
Block a user