(core) Forms post-release fixes and improvements

Summary:
Fixes misc. bugs with forms, updates Grist URLs on static form pages to link
to the new forms marketing page, and adds a forms announcement popup that's
shown next to the Add New button within a document.

Test Plan: Browser tests.

Reviewers: jarek

Reviewed By: jarek

Differential Revision: https://phab.getgrist.com/D4185
This commit is contained in:
George Gevoian
2024-02-14 16:18:09 -05:00
parent b8f32d1784
commit cd339ce7cb
43 changed files with 957 additions and 302 deletions

View File

@@ -45,4 +45,12 @@ AbstractWidget.prototype.buildColorConfigDom = function(gristDoc) {
return dom.create(CellStyle, this.field, gristDoc, this.defaultTextColor);
};
AbstractWidget.prototype.buildFormConfigDom = function() {
return null;
};
AbstractWidget.prototype.buildFormTransformConfigDom = function() {
return null;
};
module.exports = AbstractWidget;

View File

@@ -13,7 +13,7 @@ import { SingleCell } from 'app/common/TableData';
import {KoSaveableObservable} from 'app/client/models/modelUtil';
import {UploadResult} from 'app/common/uploads';
import { GristObjCode } from 'app/plugin/GristData';
import {Computed, dom, fromKo, input, onElem, styled} from 'grainjs';
import {Computed, dom, DomContents, fromKo, input, onElem, styled} from 'grainjs';
import {extname} from 'path';
@@ -69,7 +69,7 @@ export class AttachmentsWidget extends NewAbstractWidget {
);
}
public buildConfigDom(): Element {
public buildConfigDom(): DomContents {
const options = this.field.config.options;
const height = options.prop('height');
const inputRange = input(

View File

@@ -9,8 +9,7 @@ import {icon} from 'app/client/ui2018/icons';
import {ChoiceListEntry} from 'app/client/widgets/ChoiceListEntry';
import {choiceToken, DEFAULT_BACKGROUND_COLOR, DEFAULT_COLOR} from 'app/client/widgets/ChoiceToken';
import {NTextBox} from 'app/client/widgets/NTextBox';
import {WidgetType} from 'app/common/widgetTypes';
import {Computed, dom, styled, UseCB} from 'grainjs';
import {Computed, dom, styled} from 'grainjs';
export type IChoiceOptions = Style
export type ChoiceOptions = Record<string, IChoiceOptions | undefined>;
@@ -75,37 +74,9 @@ export class ChoiceTextBox extends NTextBox {
}
public buildConfigDom() {
const disabled = Computed.create(null,
use => use(this.field.disableModify)
|| use(use(this.field.column).disableEditData)
|| use(this.field.config.options.disabled('choices'))
);
const mixed = Computed.create(null,
use => !use(disabled)
&& (use(this.field.config.options.mixed('choices')) || use(this.field.config.options.mixed('choiceOptions')))
);
// If we are on forms, we don't want to show alignment options.
const notForm = (use: UseCB) => {
return use(use(this.field.viewSection).parentKey) !== WidgetType.Form;
};
return [
dom.maybe(notForm, () => super.buildConfigDom()),
cssLabel(t('CHOICES')),
cssRow(
dom.autoDispose(disabled),
dom.autoDispose(mixed),
dom.create(
ChoiceListEntry,
this._choiceValues,
this._choiceOptionsByName,
this.save.bind(this),
disabled,
mixed
)
)
super.buildConfigDom(),
this._buildChoicesConfigDom(),
];
}
@@ -113,6 +84,19 @@ export class ChoiceTextBox extends NTextBox {
return this.buildConfigDom();
}
public buildFormConfigDom() {
return [
this._buildChoicesConfigDom(),
super.buildFormConfigDom(),
];
}
public buildFormTransformConfigDom() {
return [
this._buildChoicesConfigDom(),
];
}
protected getChoiceValuesSet(): Computed<Set<string>> {
return this._choiceValuesSet;
}
@@ -128,6 +112,35 @@ export class ChoiceTextBox extends NTextBox {
};
return this.field.config.updateChoices(renames, options);
}
private _buildChoicesConfigDom() {
const disabled = Computed.create(null,
use => use(this.field.disableModify)
|| use(use(this.field.column).disableEditData)
|| use(this.field.config.options.disabled('choices'))
);
const mixed = Computed.create(null,
use => !use(disabled)
&& (use(this.field.config.options.mixed('choices')) || use(this.field.config.options.mixed('choiceOptions')))
);
return [
cssLabel(t('CHOICES')),
cssRow(
dom.autoDispose(disabled),
dom.autoDispose(mixed),
dom.create(
ChoiceListEntry,
this._choiceValues,
this._choiceOptionsByName,
this.save.bind(this),
disabled,
mixed
)
)
];
}
}
// Converts a POJO containing choice options to an ES6 Map

View File

@@ -6,11 +6,12 @@ var kd = require('../lib/koDom');
var kf = require('../lib/koForm');
var AbstractWidget = require('./AbstractWidget');
const {FieldRulesConfig} = require('app/client/components/Forms/FormConfig');
const {fromKoSave} = require('app/client/lib/fromKoSave');
const {alignmentSelect, cssButtonSelect} = require('app/client/ui2018/buttonSelect');
const {cssRow, cssLabel} = require('app/client/ui/RightPanelStyles');
const {cssLabel, cssRow} = require('app/client/ui/RightPanelStyles');
const {cssTextInput} = require("app/client/ui2018/editableLabel");
const {styled, fromKo} = require('grainjs');
const {dom: gdom, styled, fromKo} = require('grainjs');
const {select} = require('app/client/ui2018/menus');
const {dateFormatOptions} = require('app/common/parseDate');
@@ -79,6 +80,12 @@ DateTextBox.prototype.buildTransformConfigDom = function() {
return this.buildDateConfigDom();
};
DateTextBox.prototype.buildFormConfigDom = function() {
return [
gdom.create(FieldRulesConfig, this.field),
];
};
DateTextBox.prototype.buildDom = function(row) {
let value = row[this.field.colId()];
return dom('div.field_clip',

View File

@@ -305,7 +305,7 @@ export class FieldBuilder extends Disposable {
}
if (op.label === 'Reference') {
return this.gristDoc.behavioralPromptsManager.attachTip('referenceColumns', {
return this.gristDoc.behavioralPromptsManager.attachPopup('referenceColumns', {
popupOptions: {
attach: `.${cssTypeSelectMenu.className}`,
placement: 'left-start',
@@ -412,7 +412,7 @@ export class FieldBuilder extends Disposable {
return [
cssLabel(t('DATA FROM TABLE'),
kd.maybe(this._showRefConfigPopup, () => {
return dom('div', this.gristDoc.behavioralPromptsManager.attachTip(
return dom('div', this.gristDoc.behavioralPromptsManager.attachPopup(
'referenceColumnsConfig',
{
onDispose: () => this._showRefConfigPopup(false),
@@ -501,6 +501,14 @@ export class FieldBuilder extends Disposable {
);
}
public buildFormConfigDom() {
return dom('div',
kd.maybe(() => !this._isTransformingType() && this.widgetImpl(), (widget: NewAbstractWidget) =>
dom('div', widget.buildFormConfigDom())
)
);
}
/**
* Builds the FieldBuilder Options Config DOM. Calls the buildConfigDom function of its widgetImpl.
*/

View File

@@ -1,3 +1,4 @@
import { FieldRulesConfig } from 'app/client/components/Forms/FormConfig';
import { fromKoSave } from 'app/client/lib/fromKoSave';
import { DataRowModel } from 'app/client/models/DataRowModel';
import { ViewFieldRec } from 'app/client/models/entities/ViewFieldRec';
@@ -51,10 +52,16 @@ export class NTextBox extends NewAbstractWidget {
[{value: true, icon: 'Wrap'}],
toggle,
cssButtonSelect.cls('-disabled', wrapDisabled),
),
testId('tb-wrap-text')
)
)
),
testId('tb-wrap-text'),
),
),
];
}
public buildFormConfigDom(): DomContents {
return [
dom.create(FieldRulesConfig, this.field),
];
}

View File

@@ -76,6 +76,14 @@ export abstract class NewAbstractWidget extends Disposable {
return dom.create(CellStyle, this.field, gristDoc, this.defaultTextColor);
}
public buildFormConfigDom(): DomContents {
return null;
}
public buildFormTransformConfigDom(): DomContents {
return null;
}
/**
* Builds the data cell DOM.
* @param {DataRowModel} row - The rowModel object.

View File

@@ -9,9 +9,8 @@ import {icon} from 'app/client/ui2018/icons';
import {IOptionFull, select} from 'app/client/ui2018/menus';
import {NTextBox} from 'app/client/widgets/NTextBox';
import {isFullReferencingType, isVersions} from 'app/common/gristTypes';
import {WidgetType} from 'app/common/widgetTypes';
import {UIRowId} from 'app/plugin/GristAPI';
import {Computed, dom, styled, UseCB} from 'grainjs';
import {Computed, dom, styled} from 'grainjs';
const t = makeT('Reference');
@@ -49,16 +48,10 @@ export class Reference extends NTextBox {
}
public buildConfigDom() {
// If we are on forms, we don't want to show alignment options.
const notForm = (use: UseCB) => {
return use(use(this.field.viewSection).parentKey) !== WidgetType.Form;
};
return [
this.buildTransformConfigDom(),
dom.maybe(notForm, () => [
cssLabel(t('CELL FORMAT')),
super.buildConfigDom()
])
cssLabel(t('CELL FORMAT')),
super.buildConfigDom(),
];
}
@@ -76,6 +69,17 @@ export class Reference extends NTextBox {
];
}
public buildFormConfigDom() {
return [
this.buildTransformConfigDom(),
super.buildFormConfigDom(),
];
}
public buildFormTransformConfigDom() {
return this.buildTransformConfigDom();
}
public buildDom(row: DataRowModel) {
// Note: we require 2 observables here because changes to the cell value (reference id)
// and the display value (display column) are not bundled. This can cause `formattedValue`

View File

@@ -1,15 +1,22 @@
import * as commands from 'app/client/components/commands';
import { FieldRulesConfig } from 'app/client/components/Forms/FormConfig';
import { DataRowModel } from 'app/client/models/DataRowModel';
import { ViewFieldRec } from 'app/client/models/entities/ViewFieldRec';
import { KoSaveableObservable } from 'app/client/models/modelUtil';
import { NewAbstractWidget, Options } from 'app/client/widgets/NewAbstractWidget';
import { theme } from 'app/client/ui2018/cssVars';
import { dom } from 'grainjs';
import { dom, DomContents } from 'grainjs';
/**
* ToggleBase - The base class for toggle widgets, such as a checkbox or a switch.
*/
abstract class ToggleBase extends NewAbstractWidget {
public buildFormConfigDom(): DomContents {
return [
dom.create(FieldRulesConfig, this.field),
];
}
protected _addClickEventHandlers(row: DataRowModel) {
return [
dom.on('click', (event) => {