mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	(core) Filter out pages for hidden views from the page list.
Summary: - Filters out hidden pages from docModel.allPagesList (used for knowing default page, and for search iteration). - Filters out hidden pages from TreeModel (uses raw tableData, so has a different way to filter). Test Plan: WIP Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D2996
This commit is contained in:
		
							parent
							
								
									90d1340b64
								
							
						
					
					
						commit
						3edb3a6826
					
				@ -61,7 +61,6 @@ import { CursorMonitor, ViewCursorPos } from "app/client/components/CursorMonito
 | 
			
		||||
import { EditorMonitor } from "app/client/components/EditorMonitor";
 | 
			
		||||
import { FieldEditor } from "app/client/widgets/FieldEditor";
 | 
			
		||||
import { Drafts } from "app/client/components/Drafts";
 | 
			
		||||
import {findIndex} from "lodash";
 | 
			
		||||
 | 
			
		||||
const G = getBrowserGlobals('document', 'window');
 | 
			
		||||
 | 
			
		||||
@ -97,7 +96,6 @@ export class GristDoc extends DisposableWithEvents {
 | 
			
		||||
  public viewModel: ViewRec;
 | 
			
		||||
  public activeViewId: Computed<IDocPage>;
 | 
			
		||||
  public currentPageName: Observable<string>;
 | 
			
		||||
  public showDocTourTable: boolean = false;
 | 
			
		||||
  public docData: DocData;
 | 
			
		||||
  public docInfo: DocInfoRec;
 | 
			
		||||
  public docPluginManager: DocPluginManager;
 | 
			
		||||
@ -168,11 +166,7 @@ export class GristDoc extends DisposableWithEvents {
 | 
			
		||||
      if (result === 'GristDocTour') {
 | 
			
		||||
        // GristDocTour is a special table that is usually hidden from users, but putting /p/GristDocTour
 | 
			
		||||
        // in the URL navigates to it and makes it visible in the list of pages in the sidebar
 | 
			
		||||
        this.showDocTourTable = true;
 | 
			
		||||
        result = findIndex(this.docModel.views.rowModels, view => view?.name.peek() === result);
 | 
			
		||||
        if (result === -1) {
 | 
			
		||||
          result = undefined;  // not found, back to the default
 | 
			
		||||
        }
 | 
			
		||||
        result = this.docModel.views.tableData.findRow('name', result);
 | 
			
		||||
      }
 | 
			
		||||
      return result || use(defaultViewId);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@ import * as koArray from 'app/client/lib/koArray';
 | 
			
		||||
import * as koUtil from 'app/client/lib/koUtil';
 | 
			
		||||
import * as DataTableModel from 'app/client/models/DataTableModel';
 | 
			
		||||
import {DocData} from 'app/client/models/DocData';
 | 
			
		||||
import {urlState} from 'app/client/models/gristUrlState';
 | 
			
		||||
import * as MetaRowModel from 'app/client/models/MetaRowModel';
 | 
			
		||||
import * as MetaTableModel from 'app/client/models/MetaTableModel';
 | 
			
		||||
import * as rowset from 'app/client/models/rowset';
 | 
			
		||||
@ -123,11 +124,17 @@ export class DocModel {
 | 
			
		||||
  public dataTablesByRef = new Map<number, DataTableModel>();
 | 
			
		||||
 | 
			
		||||
  public allTabs: KoArray<TabBarRec> = this.tabBar.createAllRowsModel('tabPos');
 | 
			
		||||
  public allDocPages: KoArray<PageRec> = this.pages.createAllRowsModel('pagePos');
 | 
			
		||||
 | 
			
		||||
  // Excludes pages hidden by ACL rules or other reasons (e.g. doc-tour)
 | 
			
		||||
  public visibleDocPages: ko.Computed<PageRec[]>;
 | 
			
		||||
 | 
			
		||||
  // Flag for tracking whether document is in formula-editing mode
 | 
			
		||||
  public editingFormula: ko.Observable<boolean> = ko.observable(false);
 | 
			
		||||
 | 
			
		||||
  // TODO This is a temporary solution until we expose creation of doc-tours to users. This flag
 | 
			
		||||
  // is initialized once on page load. If set, then the tour page (if any) will be visible.
 | 
			
		||||
  public showDocTourTable: boolean = (urlState().state.get().docPage === 'GristDocTour');
 | 
			
		||||
 | 
			
		||||
  // List of all the metadata tables.
 | 
			
		||||
  private _metaTables: Array<MetaTableModel<any>>;
 | 
			
		||||
 | 
			
		||||
@ -158,6 +165,10 @@ export class DocModel {
 | 
			
		||||
      add: r => this._onAddTable(r),
 | 
			
		||||
      remove: r => this._onRemoveTable(r),
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Get a list of only the visible pages.
 | 
			
		||||
    const allPages = this.pages.createAllRowsModel('pagePos');
 | 
			
		||||
    this.visibleDocPages = ko.computed(() => allPages.all().filter(p => !p.isHidden()));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private _metaTableModel<TName extends keyof SchemaTypes, TRow extends IRowModel<TName>>(
 | 
			
		||||
 | 
			
		||||
@ -125,7 +125,7 @@ class FinderImpl implements IFinder {
 | 
			
		||||
 | 
			
		||||
  // Initialize the steppers. Returns false if anything goes wrong.
 | 
			
		||||
  public init(): boolean {
 | 
			
		||||
    const pages: any[] = this._gristDoc.docModel.allDocPages.peek();
 | 
			
		||||
    const pages: any[] = this._gristDoc.docModel.visibleDocPages.peek();
 | 
			
		||||
    this._pageStepper.array = pages;
 | 
			
		||||
    this._pageStepper.index = pages.findIndex(t => t.viewRef() === this._gristDoc.activeViewId.get());
 | 
			
		||||
    if (this._pageStepper.index < 0) { return false; }
 | 
			
		||||
 | 
			
		||||
@ -13,13 +13,12 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { insertPositions } from "app/client/lib/tableUtil";
 | 
			
		||||
import { BulkColValues } from "app/common/DocActions";
 | 
			
		||||
import { BulkColValues, UserAction } from "app/common/DocActions";
 | 
			
		||||
import { nativeCompare } from "app/common/gutil";
 | 
			
		||||
import { obsArray, ObsArray } from "grainjs";
 | 
			
		||||
import forEach = require("lodash/forEach");
 | 
			
		||||
import forEachRight = require("lodash/forEachRight");
 | 
			
		||||
import reverse = require("lodash/reverse");
 | 
			
		||||
import { TableData } from "./TableData";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A generic definition of a tree to use with the `TreeViewComponent`. The tree implements
 | 
			
		||||
@ -56,6 +55,12 @@ export interface TreeRecord {
 | 
			
		||||
  [key: string]: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is compatible with TableData from app/client/models/TableData.
 | 
			
		||||
export interface TreeTableData {
 | 
			
		||||
  getRecords(): TreeRecord[];
 | 
			
		||||
  sendTableActions(actions: UserAction[]): Promise<unknown>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// describes a function that builds dom for a particular record
 | 
			
		||||
type DomBuilder = (id: number) => HTMLElement;
 | 
			
		||||
 | 
			
		||||
@ -63,8 +68,8 @@ type DomBuilder = (id: number) => HTMLElement;
 | 
			
		||||
// Returns a list of the records from table that is suitable to build the tree model, ie: records
 | 
			
		||||
// are sorted by .posKey, and .indentation starts at 0 for the first records and can only increase
 | 
			
		||||
// one step at a time (but can decrease as much as you want).
 | 
			
		||||
function getRecords(table: TableData) {
 | 
			
		||||
  const records = (table.getRecords() as TreeRecord[])
 | 
			
		||||
function getRecords(table: TreeTableData) {
 | 
			
		||||
  const records = table.getRecords()
 | 
			
		||||
    .sort((a, b) => nativeCompare(a.pagePos, b.pagePos));
 | 
			
		||||
  return fixIndents(records);
 | 
			
		||||
}
 | 
			
		||||
@ -83,7 +88,7 @@ export function fixIndents(records: TreeRecord[]) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// build a tree model from a grist table storing tree view data
 | 
			
		||||
export function fromTableData(table: TableData, buildDom: DomBuilder, oldModel?: TreeModelRecord) {
 | 
			
		||||
export function fromTableData(table: TreeTableData, buildDom: DomBuilder, oldModel?: TreeModelRecord) {
 | 
			
		||||
 | 
			
		||||
  const records = getRecords(table);
 | 
			
		||||
  const storage = {table, records};
 | 
			
		||||
@ -113,7 +118,7 @@ export function fromTableData(table: TableData, buildDom: DomBuilder, oldModel?:
 | 
			
		||||
 | 
			
		||||
// a table data with all of its records as returned by getRecords(tableData)
 | 
			
		||||
interface Storage {
 | 
			
		||||
  table: TableData;
 | 
			
		||||
  table: TreeTableData;
 | 
			
		||||
  records: TreeRecord[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@ export function createDocInfoRec(this: DocInfoRec, docModel: DocModel): void {
 | 
			
		||||
    return tab ? tab.viewRef() : 0;
 | 
			
		||||
  }));
 | 
			
		||||
  this.newDefaultViewId = this.autoDispose(ko.pureComputed(() => {
 | 
			
		||||
    const page = docModel.allDocPages.at(0);
 | 
			
		||||
    const page = docModel.visibleDocPages()[0];
 | 
			
		||||
    return page ? page.viewRef() : 0;
 | 
			
		||||
  }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,13 @@ import * as ko from 'knockout';
 | 
			
		||||
// Represents a page entry in the tree of pages.
 | 
			
		||||
export interface PageRec extends IRowModel<"_grist_Pages"> {
 | 
			
		||||
  view: ko.Computed<ViewRec>;
 | 
			
		||||
  isHidden: ko.Computed<boolean>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function createPageRec(this: PageRec, docModel: DocModel): void {
 | 
			
		||||
  this.view = refRecord(docModel.views, this.viewRef);
 | 
			
		||||
  this.isHidden = ko.pureComputed(() => {
 | 
			
		||||
    const name = this.view().name();
 | 
			
		||||
    return !name || (name === 'GristDocTour' && !docModel.showDocTourTable);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,22 +4,36 @@ import { GristDoc } from "app/client/components/GristDoc";
 | 
			
		||||
import { PageRec } from "app/client/models/DocModel";
 | 
			
		||||
import { urlState } from "app/client/models/gristUrlState";
 | 
			
		||||
import * as MetaTableModel from "app/client/models/MetaTableModel";
 | 
			
		||||
import { find as findInTree, fromTableData, TreeItemRecord } from "app/client/models/TreeModel";
 | 
			
		||||
import { find as findInTree, fromTableData, TreeItemRecord, TreeRecord,
 | 
			
		||||
         TreeTableData} from "app/client/models/TreeModel";
 | 
			
		||||
import { TreeViewComponent } from "app/client/ui/TreeViewComponent";
 | 
			
		||||
import { confirmModal } from 'app/client/ui2018/modals';
 | 
			
		||||
import { buildPageDom, PageActions } from "app/client/ui2018/pages";
 | 
			
		||||
import { mod } from 'app/common/gutil';
 | 
			
		||||
import { Computed, Disposable, dom, observable, Observable } from "grainjs";
 | 
			
		||||
import { Computed, Disposable, dom, fromKo, observable, Observable } from "grainjs";
 | 
			
		||||
 | 
			
		||||
// build dom for the tree view of pages
 | 
			
		||||
export function buildPagesDom(owner: Disposable, activeDoc: GristDoc, isOpen: Observable<boolean>) {
 | 
			
		||||
  const pagesTable = activeDoc.docModel.pages;
 | 
			
		||||
  const buildDom = buildDomFromTable.bind(null, pagesTable, activeDoc);
 | 
			
		||||
 | 
			
		||||
  const records = Computed.create<TreeRecord[]>(owner, (use) =>
 | 
			
		||||
    use(activeDoc.docModel.visibleDocPages).map(page => ({
 | 
			
		||||
      id: page.getRowId(),
 | 
			
		||||
      indentation: use(page.indentation),
 | 
			
		||||
      pagePos: use(page.pagePos),
 | 
			
		||||
      viewRef: use(page.viewRef),
 | 
			
		||||
    }))
 | 
			
		||||
  );
 | 
			
		||||
  const getTreeTableData = (): TreeTableData => ({
 | 
			
		||||
    getRecords: () => records.get(),
 | 
			
		||||
    sendTableActions: (...args) => pagesTable.tableData.sendTableActions(...args),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // create the model and keep in sync with the table
 | 
			
		||||
  const model = observable(fromTableData(pagesTable.tableData, buildDom));
 | 
			
		||||
  owner.autoDispose(pagesTable.tableData.tableActionEmitter.addListener(() => {
 | 
			
		||||
    model.set(fromTableData(pagesTable.tableData, buildDom, model.get()));
 | 
			
		||||
  const model = observable(fromTableData(getTreeTableData(), buildDom));
 | 
			
		||||
  owner.autoDispose(records.addListener(() => {
 | 
			
		||||
    model.set(fromTableData(getTreeTableData(), buildDom, model.get()));
 | 
			
		||||
  }));
 | 
			
		||||
 | 
			
		||||
  // create a computed that reads the selected page from the url and return the corresponding item
 | 
			
		||||
@ -69,15 +83,7 @@ function buildDomFromTable(pagesTable: MetaTableModel<PageRec>, activeDoc: Grist
 | 
			
		||||
    actions.isRemoveDisabled = () => (docModel.allTables.all().length <= 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const maybeHiddenPageName = Computed.create(activeDoc, (use) => {
 | 
			
		||||
    const name = use(pageName);
 | 
			
		||||
    if (name === 'GristDocTour' && !activeDoc.showDocTourTable) {
 | 
			
		||||
      return '';
 | 
			
		||||
    }
 | 
			
		||||
    return name;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return buildPageDom(maybeHiddenPageName, actions, urlState().setLinkUrl({docPage: viewId}));
 | 
			
		||||
  return buildPageDom(fromKo(pageName), actions, urlState().setLinkUrl({docPage: viewId}));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Select another page in cyclic ordering of pages. Order is downard if given a positive `delta`,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user