mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Highlight rows used as a selector in linking, but do not show 'inactive' cursors.
Summary: 1. Introduces another highlight for link-selector rows, with the same color as regular selection, and allowing to overlap with regular selection. 2. Don't show "secondary" cursors (those in inactive sections), to keep a single cursor on the screen, since having multiple (which different in color) could cause confusion. 3. An unrelated improvement (prompted by a new fixture doc) is to default the active section to the top-left one (rather than the one with smallest rowId). 4. Another unrelated improvement (prompted by a test affected by the previous unrelated improvement) is to skip chart widgets when searching (previously search would step through those with an invisible "cursor"). Includes also tweaks for better testing on Arm-based Macs: - Add support for TEST_CHROME_BINARY_PATH environment variable (helpful for a Mac arm64 architecture workaround) - Remove unsetting of SELENIUM_REMOTE_URL when running headless (unlikely to affect anyone, and can be done outside the script, but interferes with the Mac workaround) Test Plan: Added a new test case that cursor and linking-selector CSS classes are present or absent appropriately. Fixed test affected by the fix to default active section. Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D3891
This commit is contained in:
@@ -147,6 +147,8 @@ function BaseView(gristDoc, viewSectionModel, options) {
|
||||
}
|
||||
}));
|
||||
|
||||
this.isLinkSource = this.autoDispose(ko.pureComputed(() => this.viewSection.linkedSections().all().length > 0));
|
||||
|
||||
// Indicated whether editing the section should be disabled given the current linking state.
|
||||
this.disableEditing = this.autoDispose(ko.computed(() => {
|
||||
const linking = this.viewSection.linkingState();
|
||||
|
||||
@@ -1226,6 +1226,8 @@ GridView.prototype.buildDom = function() {
|
||||
dom.autoDispose(fontUnderline),
|
||||
dom.autoDispose(fontStrikethrough),
|
||||
|
||||
kd.toggleClass('link_selector_row', () => self.isLinkSource() && isRowActive()),
|
||||
|
||||
// rowid dom
|
||||
dom('div.gridview_data_row_num',
|
||||
kd.style("width", ROW_NUMBER_WIDTH + 'px'),
|
||||
|
||||
@@ -172,15 +172,14 @@
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* one pixel outline around the cell, and one inside the cell */
|
||||
outline: 1px solid var(--grist-theme-cursor-inactive, var(--grist-color-inactive-cursor));
|
||||
box-shadow: inset 0 0 0 1px var(--grist-theme-cursor-inactive, var(--grist-color-inactive-cursor));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.active_cursor {
|
||||
/* one pixel outline around the cell, and one inside the cell */
|
||||
outline: 1px solid var(--grist-theme-cursor, var(--grist-color-cursor));
|
||||
box-shadow: inset 0 0 0 1px var(--grist-theme-cursor, var(--grist-color-cursor));
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +206,22 @@
|
||||
background-color: var(--grist-theme-table-header-selected-bg, var(--grist-color-medium-grey-opaque));
|
||||
}
|
||||
|
||||
.link_selector_row > .gridview_data_row_num {
|
||||
color: var(--grist-theme-left-panel-active-page-fg, white);
|
||||
background-color: var(--grist-theme-left-panel-active-page-bg, var(--grist-color-dark-bg));
|
||||
}
|
||||
|
||||
.link_selector_row > .record::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background-color: var(--grist-theme-selection, var(--grist-color-selection));
|
||||
/* z-index should be higher than '.record .field.frozen' (10) to show for frozen columns,
|
||||
* but lower than '.gridview_stick-top' (20) to stay under column headers. */
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
.gridview_data_row_info.linked_dst::before {
|
||||
position: absolute;
|
||||
content: '\25B8';
|
||||
|
||||
@@ -314,14 +314,18 @@ class FinderImpl implements IFinder {
|
||||
private _initNewSectionShown() {
|
||||
this._initNewSectionCommon();
|
||||
const viewInstance = this._sectionStepper.value.viewInstance.peek()!;
|
||||
this._rowStepper.array = viewInstance.sortedRows.getKoArray().peek() as number[];
|
||||
const skip = ['chart'].includes(this._sectionStepper.value.parentKey.peek());
|
||||
this._rowStepper.array = skip ? [] : viewInstance.sortedRows.getKoArray().peek() as number[];
|
||||
}
|
||||
|
||||
private async _initNewSectionAny() {
|
||||
const tableModel = this._initNewSectionCommon();
|
||||
|
||||
const viewInstance = this._sectionStepper.value.viewInstance.peek();
|
||||
if (viewInstance) {
|
||||
const skip = ['chart'].includes(this._sectionStepper.value.parentKey.peek());
|
||||
if (skip) {
|
||||
this._rowStepper.array = [];
|
||||
} else if (viewInstance) {
|
||||
this._rowStepper.array = viewInstance.sortedRows.getKoArray().peek() as number[];
|
||||
} else {
|
||||
// If we are searching through another page (not currently loaded), we will NOT have a
|
||||
|
||||
@@ -59,13 +59,15 @@ export function createViewRec(this: ViewRec, docModel: DocModel): void {
|
||||
const collapsed = new Set(this.activeCollapsedSections());
|
||||
const visible = all.filter(x => !collapsed.has(x.id()));
|
||||
|
||||
return visible.length > 0 ? visible[0].getRowId() : 0;
|
||||
// Default to the first leaf from layoutSpec (which corresponds to the top-left section), or
|
||||
// fall back to the first item in the list if anything goes wrong (previous behavior).
|
||||
const firstLeaf = getFirstLeaf(this.layoutSpecObj.peek());
|
||||
return visible.find(s => s.getRowId() === firstLeaf) ? firstLeaf as number :
|
||||
(visible[0]?.getRowId() || 0);
|
||||
});
|
||||
|
||||
this.activeSection = refRecord(docModel.viewSections, this.activeSectionId);
|
||||
|
||||
|
||||
|
||||
// If the active section is removed, set the next active section to be the default.
|
||||
this._isActiveSectionGone = this.autoDispose(ko.computed(() => this.activeSection()._isDeleted()));
|
||||
this.autoDispose(this._isActiveSectionGone.subscribe(gone => {
|
||||
@@ -74,3 +76,10 @@ export function createViewRec(this: ViewRec, docModel: DocModel): void {
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function getFirstLeaf(layoutSpec: BoxSpec|undefined): BoxSpec['leaf'] {
|
||||
while (layoutSpec?.children?.length) {
|
||||
layoutSpec = layoutSpec.children[0];
|
||||
}
|
||||
return layoutSpec?.leaf;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ import defaults = require('lodash/defaults');
|
||||
export interface ViewSectionRec extends IRowModel<"_grist_Views_section">, RuleOwner {
|
||||
viewFields: ko.Computed<KoArray<ViewFieldRec>>;
|
||||
|
||||
// List of sections linked from this one, i.e. for whom this one is the selector or link source.
|
||||
linkedSections: ko.Computed<KoArray<ViewSectionRec>>;
|
||||
|
||||
// All table columns associated with this view section, excluding hidden helper columns.
|
||||
columns: ko.Computed<ColumnRec[]>;
|
||||
|
||||
@@ -273,6 +276,7 @@ export interface Filter {
|
||||
|
||||
export function createViewSectionRec(this: ViewSectionRec, docModel: DocModel): void {
|
||||
this.viewFields = recordSet(this, docModel.viewFields, 'parentId', {sortBy: 'parentPos'});
|
||||
this.linkedSections = recordSet(this, docModel.viewSections, 'linkSrcSectionRef');
|
||||
|
||||
// All table columns associated with this view section, excluding any hidden helper columns.
|
||||
this.columns = this.autoDispose(ko.pureComputed(() => this.table().columns().all().filter(c => !c.isHiddenCol())));
|
||||
|
||||
@@ -549,9 +549,7 @@ export class RightPanel extends Disposable {
|
||||
]),
|
||||
|
||||
domComputed((use) => {
|
||||
const activeSectionRef = activeSection.getRowId();
|
||||
const allViewSections = use(use(viewModel.viewSections).getObservable());
|
||||
const selectorFor = allViewSections.filter((sec) => use(sec.linkSrcSectionRef) === activeSectionRef);
|
||||
const selectorFor = use(use(activeSection.linkedSections).getObservable());
|
||||
// TODO: sections should be listed following the order of appearance in the view layout (ie:
|
||||
// left/right - top/bottom);
|
||||
return selectorFor.length ? [
|
||||
|
||||
Reference in New Issue
Block a user