import {ActionGroup} from 'app/common/ActionGroup'; import {CellValue, TableDataAction, UserAction} from 'app/common/DocActions'; import {FormulaProperties} from 'app/common/GranularAccessClause'; import {FetchUrlOptions, UploadResult} from 'app/common/uploads'; import {DocStateComparison, PermissionData, UserAccessData} from 'app/common/UserAPI'; import {ParseOptions} from 'app/plugin/FileParserAPI'; import {IMessage} from 'grain-rpc'; export interface ApplyUAOptions { desc?: string; // Overrides the description of the action. otherId?: number; // For undo/redo; the actionNum of the original action to which it applies. linkId?: number; // For bundled actions, actionNum of the previous action in the bundle. bestEffort?: boolean; // If set, action may be applied in part if it cannot be applied completely. parseStrings?: boolean; // If true, parses string values in some actions based on the column } export interface ApplyUAResult { actionNum: number; // number of the action that got recorded. retValues: any[]; // array of return values, one for each of the passed-in user actions. isModification: boolean; // true if document was modified. } export interface DataSourceTransformed { // Identifies the upload, which may include multiple files. uploadId: number; // For each file in the upload, the transform rules for that file. transforms: TransformRuleMap[]; } export interface TransformRuleMap { [origTableName: string]: TransformRule; } // Special values for import destinations; null means "new table", "" means skip table. // Both special options exposed as consts. export type DestId = string | null; export const NEW_TABLE = null; export const SKIP_TABLE = ""; export interface TransformRule { destTableId: DestId; destCols: TransformColumn[]; sourceCols: string[]; } export interface TransformColumn { label: string; colId: string|null; type: string; formula: string; widgetOptions: string; } export interface ImportResult { options: ParseOptions; tables: ImportTableResult[]; } export interface ImportTableResult { hiddenTableId: string; uploadFileIndex: number; // Index into upload.files array, for the file responsible for this table. origTableName: string; transformSectionRef: number; destTableId: string|null; } export interface ImportOptions { parseOptions?: ParseOptions; // Options for parsing the source file. mergeOptionMaps?: MergeOptionsMap[]; // Options for merging fields, indexed by uploadFileIndex. } export interface MergeOptionsMap { // Map of original GristTable name of imported table to its merge options, if any. [origTableName: string]: MergeOptions|undefined; } export interface MergeOptions { mergeCols: string[]; // Columns to use as merge keys for incremental imports. mergeStrategy: MergeStrategy; // Determines how matched records should be merged between 2 tables. } export interface MergeStrategy { type: 'replace-with-nonblank-source' | 'replace-all-fields' | 'replace-blank-fields-only'; } /** * Represents a query for Grist data. The tableId is required. An empty set of filters indicates * the full table. Examples: * {tableId: "Projects", filters: {}} * {tableId: "Employees", filters: {Status: ["Active"], Dept: ["Sales", "HR"]}} */ interface BaseQuery { tableId: string; filters: QueryFilters; } /** * Query that can only be used on the client side. * Allows filtering with more complex operations. */ export interface ClientQuery extends BaseQuery { operations: { [colId: string]: QueryOperation; }; } /** * Query intended to be sent to a server. */ export interface ServerQuery extends BaseQuery { // Queries to server for onDemand tables will set a limit to avoid bringing down the browser. limit?: number; } /** * Type of the filters option to queries. */ export interface QueryFilters { // TODO: check if "any" can be replaced with "CellValue". [colId: string]: any[]; } // - in: value should be contained in filters array // - intersects: value should be a list with some overlap with filters array // - empty: value should be falsy (e.g. null) or an empty list, filters is ignored export type QueryOperation = "in" | "intersects" | "empty"; /** * Response from useQuerySet(). A query returns data AND creates a subscription to receive * DocActions that affect this data. The querySubId field identifies this subscription, and must * be used in a disposeQuerySet() call to unsubscribe. */ export interface QueryResult { querySubId: number; // ID of the subscription, to use with disposeQuerySet. tableData: TableDataAction; } /** * Result of a fork operation, with newly minted ids. * For a document with docId XXXXX and urlId UUUUU, the fork will have a * docId of XXXXX~FORKID[~USERID] and a urlId of UUUUU~FORKID[~USERID]. */ export interface ForkResult { docId: string; urlId: string; } /** * An extension of PermissionData to cover not just users with whom a document is shared, * but also users mentioned in the document (in user attribute tables), and suggested * example users. This is for use in the "View As" feature of the access rules page. */ export interface PermissionDataWithExtraUsers extends PermissionData { attributeTableUsers: UserAccessData[]; exampleUsers: UserAccessData[]; } /** * Basic metadata about a table returned by `getAclResources()`. */ export interface AclTableDescription { title: string; // Raw data widget title colIds: string[]; // IDs of all columns in table groupByColLabels: string[] | null; // Labels of groupby columns for summary tables, or null. } export function getTableTitle(table: AclTableDescription): string { let {title} = table; if (table.groupByColLabels) { title += ' ' + summaryGroupByDescription(table.groupByColLabels); } return title; } export function summaryGroupByDescription(groupByColumnLabels: string[]): string { return `[${groupByColumnLabels.length ? 'by ' + groupByColumnLabels.join(", ") : "Totals"}]`; } export interface ActiveDocAPI { /** * Closes a document, and unsubscribes from its userAction events. */ closeDoc(): Promise; /** * Fetches a particular table from the data engine to return to the client. */ fetchTable(tableId: string): Promise; /** * Fetches the generated Python code for this document. (TODO rename this misnomer.) */ fetchTableSchema(): Promise; /** * Makes a query (documented elsewhere) and subscribes to it, so that the client receives * docActions that affect this query's results. The subscription remains functional even when * tables or columns get renamed. */ useQuerySet(query: ServerQuery): Promise; /** * Removes the subscription to a Query, identified by QueryResult.querySubId, so that the * client stops receiving docActions relevant only to that query. */ disposeQuerySet(querySubId: number): Promise; /** * Applies an array of user actions to the document. */ applyUserActions(actions: UserAction[], options?: ApplyUAOptions): Promise; /** * A variant of applyUserActions where actions are passed in by ids (actionNum, actionHash) * rather than by value. */ applyUserActionsById(actionNums: number[], actionHashes: string[], undo: boolean, options?: ApplyUAOptions): Promise; /** * Imports files, removes previously created temporary hidden tables and creates the new ones. */ importFiles(dataSource: DataSourceTransformed, parseOptions: ParseOptions, prevTableIds: string[]): Promise; /** * Finishes import files, creates the new tables, and cleans up temporary hidden tables and uploads. */ finishImportFiles(dataSource: DataSourceTransformed, prevTableIds: string[], options: ImportOptions): Promise; /** * Cancels import files, cleans up temporary hidden tables and uploads. */ cancelImportFiles(uploadId: number, prevTableIds: string[]): Promise; /** * Returns a diff of changes that will be applied to the destination table from `transformRule` * if the data from `hiddenTableId` is imported with the specified `mergeOptions`. */ generateImportDiff(hiddenTableId: string, transformRule: TransformRule, mergeOptions: MergeOptions): Promise; /** * Saves attachments from a given upload and creates an entry for them in the database. It * returns the list of rowIds for the rows created in the _grist_Attachments table. */ addAttachments(uploadId: number): Promise; /** * Returns up to n columns in the document, or a specific table, which contain the given values. * Columns are returned ordered from best to worst based on an estimate for number of matches. */ findColFromValues(values: any[], n: number, optTableId?: string): Promise; /** * Returns cell value with an error message (traceback) for one invalid formula cell. */ getFormulaError(tableId: string, colId: string, rowId: number): Promise; /** * Fetch content at a url. */ fetchURL(url: string, options?: FetchUrlOptions): Promise; /** * Find and return a list of auto-complete suggestions that start with `txt`, when editing a * formula in table `tableId` and column `columnId`. */ autocomplete(txt: string, tableId: string, columnId: string): Promise; /** * Removes the current instance from the doc. */ removeInstanceFromDoc(): Promise; /** * Get recent actions in ActionGroup format with summaries included. */ getActionSummaries(): Promise; /** * Initiates user actions bandling for undo. */ startBundleUserActions(): Promise; /** * Stopes user actions bandling for undo. */ stopBundleUserActions(): Promise; /** * Forward a grain-rpc message to a given plugin. */ forwardPluginRpc(pluginId: string, msg: IMessage): Promise; /** * Reload documents plugins. */ reloadPlugins(): Promise; /** * Immediately close the document and data engine, to be reloaded from scratch, and cause all * browser clients to reopen it. */ reloadDoc(): Promise; /** * Prepare a fork of the document, and return the id(s) of the fork. */ fork(): Promise; /** * Check if an ACL formula is valid. If not, will throw an error with an explanation. */ checkAclFormula(text: string): Promise; /** * Returns the full set of tableIds, with the list of colIds for each table. This is intended * for editing ACLs. It is only available to users who can edit ACLs, and lists all resources * regardless of rules that may block access to them. */ getAclResources(): Promise<{[tableId: string]: AclTableDescription}>; /** * Wait for document to finish initializing. */ waitForInitialization(): Promise; /** * Get users that are worth proposing to "View As" for access control purposes. */ getUsersForViewAs(): Promise; }