2024-02-21 19:22:01 +00:00
|
|
|
import {BaseAPI, IOptions} from 'app/common/BaseAPI';
|
|
|
|
import {CellValue, ColValues} from 'app/common/DocActions';
|
2024-02-22 17:01:17 +00:00
|
|
|
import {addCurrentOrgToPath} from 'app/common/urlUtils';
|
2024-02-21 19:22:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Form and associated field metadata from a Grist view section.
|
|
|
|
*
|
|
|
|
* Includes the layout of the form, metadata such as the form title, and
|
|
|
|
* a map of data for each field in the form. All of this is used to build a
|
|
|
|
* submittable version of the form (see `FormRenderer.ts`, which handles the
|
|
|
|
* actual building of forms).
|
|
|
|
*/
|
|
|
|
export interface Form {
|
|
|
|
formFieldsById: Record<number, FormField>;
|
|
|
|
formLayoutSpec: string;
|
|
|
|
formTitle: string;
|
|
|
|
formTableId: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Metadata for a field in a form.
|
|
|
|
*
|
|
|
|
* Form fields are directly related to Grist fields; the former is based on data
|
|
|
|
* from the latter, with additional metadata specific to forms, like whether a
|
|
|
|
* form field is required. All of this is used to build a field in a submittable
|
|
|
|
* version of the form (see `FormRenderer.ts`, which handles the actual building
|
|
|
|
* of forms).
|
|
|
|
*/
|
|
|
|
export interface FormField {
|
|
|
|
/** The field label. Defaults to the Grist column label or id. */
|
|
|
|
question: string;
|
|
|
|
/** The field description. */
|
|
|
|
description: string;
|
|
|
|
/** The Grist column id of the field. */
|
|
|
|
colId: string;
|
|
|
|
/** The Grist column type of the field (e.g. "Text"). */
|
|
|
|
type: string;
|
|
|
|
/** Additional field options. */
|
|
|
|
options: FormFieldOptions;
|
|
|
|
/** Populated with data from a referenced table. Only set if `type` is a Reference type. */
|
|
|
|
refValues: [number, CellValue][] | null;
|
|
|
|
}
|
|
|
|
|
2024-04-11 06:50:30 +00:00
|
|
|
export interface FormFieldOptions {
|
|
|
|
/** Choices for a Choice or Choice List field. */
|
2024-02-21 19:22:01 +00:00
|
|
|
choices?: string[];
|
2024-04-11 06:50:30 +00:00
|
|
|
/** Text or Any field format. Defaults to `"singleline"`. */
|
|
|
|
formTextFormat?: FormTextFormat;
|
|
|
|
/** Number of lines/rows for the `"multiline"` option of `formTextFormat`. Defaults to `3`. */
|
|
|
|
formTextLineCount?: number;
|
|
|
|
/** Numeric or Int field format. Defaults to `"text"`. */
|
|
|
|
formNumberFormat?: FormNumberFormat;
|
|
|
|
/** Toggle field format. Defaults to `"switch"`. */
|
|
|
|
formToggleFormat?: FormToggleFormat;
|
|
|
|
/** Choice or Reference field format. Defaults to `"select"`. */
|
|
|
|
formSelectFormat?: FormSelectFormat;
|
|
|
|
/**
|
|
|
|
* Field options alignment.
|
|
|
|
*
|
|
|
|
* Only applicable to Choice List and Reference List fields, and Choice and Reference fields
|
|
|
|
* when `formSelectFormat` is `"radio"`.
|
|
|
|
*
|
|
|
|
* Defaults to `"vertical"`.
|
|
|
|
*/
|
|
|
|
formOptionsAlignment?: FormOptionsAlignment;
|
|
|
|
/**
|
|
|
|
* Field options sort order.
|
|
|
|
*
|
|
|
|
* Only applicable to Choice, Choice List, Reference, and Reference List fields.
|
|
|
|
*
|
|
|
|
* Defaults to `"default"`.
|
|
|
|
*/
|
|
|
|
formOptionsSortOrder?: FormOptionsSortOrder;
|
|
|
|
/** True if the field is required. Defaults to `false`. */
|
|
|
|
formRequired?: boolean;
|
2024-02-21 19:22:01 +00:00
|
|
|
}
|
|
|
|
|
2024-04-11 06:50:30 +00:00
|
|
|
export type FormTextFormat = 'singleline' | 'multiline';
|
|
|
|
|
|
|
|
export type FormNumberFormat = 'text' | 'spinner';
|
|
|
|
|
|
|
|
export type FormToggleFormat = 'switch' | 'checkbox';
|
|
|
|
|
|
|
|
export type FormSelectFormat = 'select' | 'radio';
|
|
|
|
|
|
|
|
export type FormOptionsAlignment = 'vertical' | 'horizontal';
|
|
|
|
|
|
|
|
export type FormOptionsSortOrder = 'default' | 'ascending' | 'descending';
|
|
|
|
|
2024-02-21 19:22:01 +00:00
|
|
|
export interface FormAPI {
|
|
|
|
getForm(options: GetFormOptions): Promise<Form>;
|
|
|
|
createRecord(options: CreateRecordOptions): Promise<void>;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface GetFormCommonOptions {
|
|
|
|
vsId: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface GetFormWithDocIdOptions extends GetFormCommonOptions {
|
|
|
|
docId: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface GetFormWithShareKeyOptions extends GetFormCommonOptions {
|
|
|
|
shareKey: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
type GetFormOptions = GetFormWithDocIdOptions | GetFormWithShareKeyOptions;
|
|
|
|
|
|
|
|
interface CreateRecordCommonOptions {
|
|
|
|
tableId: string;
|
|
|
|
colValues: ColValues;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface CreateRecordWithDocIdOptions extends CreateRecordCommonOptions {
|
|
|
|
docId: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface CreateRecordWithShareKeyOptions extends CreateRecordCommonOptions {
|
|
|
|
shareKey: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
type CreateRecordOptions = CreateRecordWithDocIdOptions | CreateRecordWithShareKeyOptions;
|
|
|
|
|
|
|
|
export class FormAPIImpl extends BaseAPI implements FormAPI {
|
2024-02-22 17:01:17 +00:00
|
|
|
constructor(private _homeUrl: string, options: IOptions = {}) {
|
2024-02-21 19:22:01 +00:00
|
|
|
super(options);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async getForm(options: GetFormOptions): Promise<Form> {
|
|
|
|
if ('docId' in options) {
|
|
|
|
const {docId, vsId} = options;
|
|
|
|
return this.requestJson(`${this._url}/api/docs/${docId}/forms/${vsId}`, {method: 'GET'});
|
|
|
|
} else {
|
|
|
|
const {shareKey, vsId} = options;
|
|
|
|
return this.requestJson(`${this._url}/api/s/${shareKey}/forms/${vsId}`, {method: 'GET'});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public async createRecord(options: CreateRecordOptions): Promise<void> {
|
|
|
|
if ('docId' in options) {
|
|
|
|
const {docId, tableId, colValues} = options;
|
|
|
|
return this.requestJson(`${this._url}/api/docs/${docId}/tables/${tableId}/records`, {
|
|
|
|
method: 'POST',
|
|
|
|
body: JSON.stringify({records: [{fields: colValues}]}),
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
const {shareKey, tableId, colValues} = options;
|
2024-03-20 14:51:59 +00:00
|
|
|
const url = new URL(`${this._url}/api/s/${shareKey}/tables/${tableId}/records`);
|
|
|
|
url.searchParams.set('utm_source', 'grist-forms');
|
|
|
|
return this.requestJson(url.href, {
|
2024-02-21 19:22:01 +00:00
|
|
|
method: 'POST',
|
|
|
|
body: JSON.stringify({records: [{fields: colValues}]}),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2024-02-22 17:01:17 +00:00
|
|
|
|
|
|
|
private get _url(): string {
|
|
|
|
return addCurrentOrgToPath(this._homeUrl);
|
|
|
|
}
|
2024-02-21 19:22:01 +00:00
|
|
|
}
|