2020-10-02 15:10:00 +00:00
|
|
|
import {KoArray} from 'app/client/lib/koArray';
|
2022-02-07 14:02:26 +00:00
|
|
|
import {DocModel, IRowModel, recordSet, refRecord, ViewSectionRec} from 'app/client/models/DocModel';
|
2021-11-30 17:46:21 +00:00
|
|
|
import {ColumnRec, ValidationRec, ViewRec} from 'app/client/models/DocModel';
|
2022-04-27 17:46:24 +00:00
|
|
|
import * as modelUtil from 'app/client/models/modelUtil';
|
2022-07-18 11:57:56 +00:00
|
|
|
import {summaryGroupByDescription} from 'app/common/ActiveDocAPI';
|
2020-10-02 15:10:00 +00:00
|
|
|
import {MANUALSORT} from 'app/common/gristTypes';
|
|
|
|
import * as ko from 'knockout';
|
2022-07-04 14:14:55 +00:00
|
|
|
import randomcolor from 'randomcolor';
|
2020-10-02 15:10:00 +00:00
|
|
|
|
|
|
|
// Represents a user-defined table.
|
|
|
|
export interface TableRec extends IRowModel<"_grist_Tables"> {
|
|
|
|
columns: ko.Computed<KoArray<ColumnRec>>;
|
2023-10-17 18:14:54 +00:00
|
|
|
visibleColumns: ko.Computed<ColumnRec[]>;
|
2020-10-02 15:10:00 +00:00
|
|
|
validations: ko.Computed<KoArray<ValidationRec>>;
|
|
|
|
|
|
|
|
primaryView: ko.Computed<ViewRec>;
|
2022-02-07 14:02:26 +00:00
|
|
|
rawViewSection: ko.Computed<ViewSectionRec>;
|
2023-11-20 00:46:32 +00:00
|
|
|
recordCardViewSection: ko.Computed<ViewSectionRec>;
|
2020-10-02 15:10:00 +00:00
|
|
|
summarySource: ko.Computed<TableRec>;
|
|
|
|
|
|
|
|
// A Set object of colRefs for all summarySourceCols of table.
|
|
|
|
summarySourceColRefs: ko.Computed<Set<number>>;
|
|
|
|
|
|
|
|
// tableId for normal tables, or tableId of the source table for summary tables.
|
|
|
|
primaryTableId: ko.Computed<string>;
|
|
|
|
|
|
|
|
// The list of grouped by columns.
|
|
|
|
groupByColumns: ko.Computed<ColumnRec[]>;
|
2022-04-27 17:46:24 +00:00
|
|
|
// Grouping description.
|
|
|
|
groupDesc: ko.PureComputed<string>;
|
|
|
|
// Name of the data table - title of the rawViewSection
|
|
|
|
// for summary table it is name of primary table.
|
|
|
|
tableName: modelUtil.KoSaveableObservable<string>;
|
|
|
|
// Table name with a default value (which is tableId).
|
|
|
|
tableNameDef: modelUtil.KoSaveableObservable<string>;
|
2022-07-06 07:41:09 +00:00
|
|
|
// Like tableNameDef, but formatted to be more suitable for displaying to
|
|
|
|
// users (e.g. including group columns for summary tables).
|
|
|
|
formattedTableName: ko.PureComputed<string>;
|
2022-04-27 17:46:24 +00:00
|
|
|
// If user can select this table in various places.
|
|
|
|
// Note: Some hidden tables can still be visible on RawData view.
|
|
|
|
isHidden: ko.Computed<boolean>;
|
2020-10-02 15:10:00 +00:00
|
|
|
|
|
|
|
tableColor: string;
|
|
|
|
disableAddRemoveRows: ko.Computed<boolean>;
|
|
|
|
supportsManualSort: ko.Computed<boolean>;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function createTableRec(this: TableRec, docModel: DocModel): void {
|
|
|
|
this.columns = recordSet(this, docModel.columns, 'parentId', {sortBy: 'parentPos'});
|
2023-10-17 18:14:54 +00:00
|
|
|
this.visibleColumns = this.autoDispose(ko.pureComputed(() =>
|
|
|
|
this.columns().all().filter(c => !c.isHiddenCol())));
|
2020-10-02 15:10:00 +00:00
|
|
|
this.validations = recordSet(this, docModel.validations, 'tableRef');
|
|
|
|
|
|
|
|
this.primaryView = refRecord(docModel.views, this.primaryViewId);
|
2022-02-07 14:02:26 +00:00
|
|
|
this.rawViewSection = refRecord(docModel.viewSections, this.rawViewSectionRef);
|
2023-11-20 00:46:32 +00:00
|
|
|
this.recordCardViewSection = refRecord(docModel.viewSections, this.recordCardViewSectionRef);
|
2020-10-02 15:10:00 +00:00
|
|
|
this.summarySource = refRecord(docModel.tables, this.summarySourceTable);
|
2022-04-27 17:46:24 +00:00
|
|
|
this.isHidden = this.autoDispose(
|
|
|
|
// This is repeated logic from isHiddenTable.
|
2022-07-21 13:46:29 +00:00
|
|
|
ko.pureComputed(() => !this.tableId() || !!this.summarySourceTable() || this.tableId().startsWith("GristHidden_"))
|
2022-04-27 17:46:24 +00:00
|
|
|
);
|
2020-10-02 15:10:00 +00:00
|
|
|
|
|
|
|
// A Set object of colRefs for all summarySourceCols of this table.
|
|
|
|
this.summarySourceColRefs = this.autoDispose(ko.pureComputed(() => new Set(
|
|
|
|
this.columns().all().map(c => c.summarySourceCol()).filter(colRef => colRef))));
|
|
|
|
|
|
|
|
// tableId for normal tables, or tableId of the source table for summary tables.
|
|
|
|
this.primaryTableId = ko.pureComputed(() =>
|
|
|
|
this.summarySourceTable() ? this.summarySource().tableId() : this.tableId());
|
|
|
|
|
|
|
|
this.groupByColumns = ko.pureComputed(() => this.columns().all().filter(c => c.summarySourceCol()));
|
|
|
|
|
2022-04-27 17:46:24 +00:00
|
|
|
this.groupDesc = ko.pureComputed(() => {
|
|
|
|
if (!this.summarySourceTable()) {
|
|
|
|
return '';
|
2020-10-02 15:10:00 +00:00
|
|
|
}
|
2022-07-18 11:57:56 +00:00
|
|
|
return summaryGroupByDescription(this.groupByColumns().map(c => c.label()));
|
2020-10-02 15:10:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// TODO: We should save this value and let users change it.
|
|
|
|
this.tableColor = randomcolor({
|
|
|
|
luminosity: 'light',
|
|
|
|
seed: typeof this.id() === 'number' ? 5 * this.id() : this.id()
|
|
|
|
});
|
|
|
|
|
|
|
|
this.disableAddRemoveRows = ko.pureComputed(() => Boolean(this.summarySourceTable()));
|
|
|
|
|
|
|
|
this.supportsManualSort = ko.pureComputed(() => this.columns().all().some(c => c.colId() === MANUALSORT));
|
2022-04-27 17:46:24 +00:00
|
|
|
|
|
|
|
this.tableName = modelUtil.savingComputed({
|
|
|
|
read: () => {
|
|
|
|
if (this.isDisposed()) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
if (this.summarySourceTable()) {
|
|
|
|
return this.summarySource().rawViewSection().title();
|
|
|
|
} else {
|
|
|
|
// Need to be extra careful here, rawViewSection might be disposed.
|
|
|
|
if (this.rawViewSection().isDisposed()) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
return this.rawViewSection().title();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
write: (setter, val) => {
|
|
|
|
if (this.summarySourceTable()) {
|
|
|
|
setter(this.summarySource().rawViewSection().title, val);
|
|
|
|
} else {
|
|
|
|
setter(this.rawViewSection().title, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.tableNameDef = modelUtil.fieldWithDefault(
|
|
|
|
this.tableName,
|
|
|
|
// TableId will be null/undefined when ACL will restrict access to it.
|
|
|
|
ko.computed(() => {
|
|
|
|
// During table removal, we could be disposed.
|
|
|
|
if (this.isDisposed()) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
const table = this.summarySourceTable() ? this.summarySource() : this;
|
|
|
|
return table.tableId() || '';
|
|
|
|
})
|
|
|
|
);
|
2022-07-06 07:41:09 +00:00
|
|
|
this.formattedTableName = ko.pureComputed(() => {
|
|
|
|
return this.summarySourceTable()
|
|
|
|
? `${this.tableNameDef()} ${this.groupDesc()}`
|
|
|
|
: this.tableNameDef();
|
|
|
|
});
|
2020-10-02 15:10:00 +00:00
|
|
|
}
|