mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Form Publishing
Summary: Adds initial implementation of form publishing, built upon WYSIWYS shares. A simple UI for publishing and unpublishing forms is included. Test Plan: Browser tests. Reviewers: jarek Reviewed By: jarek Subscribers: paulfitz, jarek Differential Revision: https://phab.getgrist.com/D4154
This commit is contained in:
@@ -34,6 +34,7 @@ import {ColumnRec, createColumnRec} from 'app/client/models/entities/ColumnRec';
|
||||
import {createDocInfoRec, DocInfoRec} from 'app/client/models/entities/DocInfoRec';
|
||||
import {createFilterRec, FilterRec} from 'app/client/models/entities/FilterRec';
|
||||
import {createPageRec, PageRec} from 'app/client/models/entities/PageRec';
|
||||
import {createShareRec, ShareRec} from 'app/client/models/entities/ShareRec';
|
||||
import {createTabBarRec, TabBarRec} from 'app/client/models/entities/TabBarRec';
|
||||
import {createTableRec, TableRec} from 'app/client/models/entities/TableRec';
|
||||
import {createValidationRec, ValidationRec} from 'app/client/models/entities/ValidationRec';
|
||||
@@ -127,6 +128,7 @@ export class DocModel {
|
||||
public tabBar: MTM<TabBarRec> = this._metaTableModel("_grist_TabBar", createTabBarRec);
|
||||
public validations: MTM<ValidationRec> = this._metaTableModel("_grist_Validations", createValidationRec);
|
||||
public pages: MTM<PageRec> = this._metaTableModel("_grist_Pages", createPageRec);
|
||||
public shares: MTM<ShareRec> = this._metaTableModel("_grist_Shares", createShareRec);
|
||||
public rules: MTM<ACLRuleRec> = this._metaTableModel("_grist_ACLRules", createACLRuleRec);
|
||||
public filters: MTM<FilterRec> = this._metaTableModel("_grist_Filters", createFilterRec);
|
||||
public cells: MTM<CellRec> = this._metaTableModel("_grist_Cells", createCellRec);
|
||||
@@ -149,6 +151,7 @@ export class DocModel {
|
||||
|
||||
public allTabs: KoArray<TabBarRec> = this.tabBar.createAllRowsModel('tabPos');
|
||||
|
||||
public allPages: ko.Computed<PageRec[]>;
|
||||
/** Pages that are shown in the menu. These can include censored pages if they have children. */
|
||||
public menuPages: ko.Computed<PageRec[]>;
|
||||
// Excludes pages hidden by ACL rules or other reasons (e.g. doc-tour)
|
||||
@@ -217,8 +220,9 @@ export class DocModel {
|
||||
|
||||
// Get a list of only the visible pages.
|
||||
const allPages = this.pages.createAllRowsModel('pagePos');
|
||||
this.allPages = ko.computed(() => allPages.all());
|
||||
this.menuPages = ko.computed(() => {
|
||||
const pagesToShow = allPages.all().filter(p => !p.isSpecial()).sort((a, b) => a.pagePos() - b.pagePos());
|
||||
const pagesToShow = this.allPages().filter(p => !p.isSpecial()).sort((a, b) => a.pagePos() - b.pagePos());
|
||||
// Helper to find all children of a page.
|
||||
const children = memoize((page: PageRec) => {
|
||||
const following = pagesToShow.slice(pagesToShow.indexOf(page) + 1);
|
||||
@@ -230,7 +234,7 @@ export class DocModel {
|
||||
const hide = memoize((page: PageRec): boolean => page.isCensored() && children(page).every(p => hide(p)));
|
||||
return pagesToShow.filter(p => !hide(p));
|
||||
});
|
||||
this.visibleDocPages = ko.computed(() => allPages.all().filter(p => !p.isHidden()));
|
||||
this.visibleDocPages = ko.computed(() => this.allPages().filter(p => !p.isHidden()));
|
||||
|
||||
this.hasDocTour = ko.computed(() => this.visibleTableIds.all().includes('GristDocTour'));
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {DocModel, IRowModel, refRecord, ViewRec} from 'app/client/models/DocModel';
|
||||
import {ShareRec} from 'app/client/models/entities/ShareRec';
|
||||
import * as ko from 'knockout';
|
||||
|
||||
// Represents a page entry in the tree of pages.
|
||||
@@ -7,6 +8,7 @@ export interface PageRec extends IRowModel<"_grist_Pages"> {
|
||||
isHidden: ko.Computed<boolean>;
|
||||
isCensored: ko.Computed<boolean>;
|
||||
isSpecial: ko.Computed<boolean>;
|
||||
share: ko.Computed<ShareRec>;
|
||||
}
|
||||
|
||||
export function createPageRec(this: PageRec, docModel: DocModel): void {
|
||||
@@ -36,4 +38,5 @@ export function createPageRec(this: PageRec, docModel: DocModel): void {
|
||||
this.isHidden = ko.pureComputed(() => {
|
||||
return this.isCensored() || this.isSpecial();
|
||||
});
|
||||
this.share = refRecord(docModel.shares, this.shareRef);
|
||||
}
|
||||
|
||||
10
app/client/models/entities/ShareRec.ts
Normal file
10
app/client/models/entities/ShareRec.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import {IRowModel} from 'app/client/models/DocModel';
|
||||
import * as modelUtil from 'app/client/models/modelUtil';
|
||||
|
||||
export interface ShareRec extends IRowModel<"_grist_Shares"> {
|
||||
optionsObj: modelUtil.SaveableObjObservable<any>;
|
||||
}
|
||||
|
||||
export function createShareRec(this: ShareRec): void {
|
||||
this.optionsObj = modelUtil.jsonObservable(this.options);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import {BoxSpec} from 'app/client/components/Layout';
|
||||
import {KoArray} from 'app/client/lib/koArray';
|
||||
import * as koUtil from 'app/client/lib/koUtil';
|
||||
import {DocModel, IRowModel, recordSet, refRecord} from 'app/client/models/DocModel';
|
||||
import {DocModel, IRowModel, PageRec, recordSet, refRecord} from 'app/client/models/DocModel';
|
||||
import {TabBarRec, ViewSectionRec} from 'app/client/models/DocModel';
|
||||
import * as modelUtil from 'app/client/models/modelUtil';
|
||||
import * as ko from 'knockout';
|
||||
@@ -30,6 +30,8 @@ export interface ViewRec extends IRowModel<"_grist_Views"> {
|
||||
|
||||
// If the active section is removed, set the next active section to be the default.
|
||||
_isActiveSectionGone: ko.Computed<boolean>;
|
||||
|
||||
page: ko.Computed<PageRec|null>;
|
||||
}
|
||||
|
||||
export function createViewRec(this: ViewRec, docModel: DocModel): void {
|
||||
@@ -76,6 +78,11 @@ export function createViewRec(this: ViewRec, docModel: DocModel): void {
|
||||
this.activeSectionId(0);
|
||||
}
|
||||
}));
|
||||
|
||||
this.page = this.autoDispose(ko.pureComputed(() => {
|
||||
const viewRef = this.id();
|
||||
return docModel.allPages().find(p => p.viewRef() === viewRef) ?? null;
|
||||
}));
|
||||
}
|
||||
|
||||
function getFirstLeaf(layoutSpec: BoxSpec|undefined): BoxSpec['leaf'] {
|
||||
|
||||
@@ -71,6 +71,7 @@ export interface ViewSectionRec extends IRowModel<"_grist_Views_section">, RuleO
|
||||
columns: ko.Computed<ColumnRec[]>;
|
||||
|
||||
optionsObj: modelUtil.SaveableObjObservable<any>;
|
||||
shareOptionsObj: modelUtil.SaveableObjObservable<any>;
|
||||
|
||||
customDef: CustomViewSectionDef;
|
||||
|
||||
@@ -380,6 +381,7 @@ export function createViewSectionRec(this: ViewSectionRec, docModel: DocModel):
|
||||
};
|
||||
this.optionsObj = modelUtil.jsonObservable(this.options,
|
||||
(obj: any) => defaults(obj || {}, defaultOptions));
|
||||
this.shareOptionsObj = modelUtil.jsonObservable(this.shareOptions);
|
||||
|
||||
const customViewDefaults = {
|
||||
mode: 'url',
|
||||
|
||||
Reference in New Issue
Block a user