mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) updates from grist-core
This commit is contained in:
commit
be8c053922
@ -60,7 +60,7 @@ or browse [our extensive documentation](https://support.getgrist.com).
|
||||
|
||||
There are docker images set up for individual use, or (with some
|
||||
configuration) for self-hosting. Grist Labs offers a hosted service
|
||||
at [https://docs.getgrist.com](https://docs.getgrist.com).
|
||||
at [docs.getgrist.com](https://docs.getgrist.com).
|
||||
|
||||
To run Grist running on your computer with [Docker](https://www.docker.com/get-started), do:
|
||||
|
||||
@ -76,10 +76,10 @@ and export documents. To preserve your work across docker runs, share a director
|
||||
docker run -p 8484:8484 -v $PWD/persist:/persist -it gristlabs/grist
|
||||
```
|
||||
|
||||
Get templates at https://templates.getgrist.com/ for payroll,
|
||||
Get templates at [templates.getgrist.com](https://templates.getgrist.com) for payroll,
|
||||
inventory management, invoicing, D&D encounter tracking, and a lot
|
||||
more, or use any document you've created on
|
||||
[https://docs.getgrist.com](docs.getgrist.com).
|
||||
[docs.getgrist.com](https://docs.getgrist.com).
|
||||
|
||||
If you need to change the port Grist runs on, set a `PORT` variable, don't just change the
|
||||
port mapping:
|
||||
|
@ -99,7 +99,7 @@ function makePermissionSet(bits: PermissionKey[], makeValue: (bit: PermissionKey
|
||||
return pset;
|
||||
}
|
||||
|
||||
// Helper for a tick (checkmark) icon, replacing it with an equialent space when not shown.
|
||||
// Helper for a tick (checkmark) icon, replacing it with an equivalent space when not shown.
|
||||
function tick(show: boolean) {
|
||||
return show ? menuIcon('Tick') : cssMenuIconSpace();
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ function BaseView(gristDoc, viewSectionModel, options) {
|
||||
this._isLoading = ko.observable(true);
|
||||
this._pendingCursorPos = this.viewSection.lastCursorPos;
|
||||
|
||||
// Initialize the cursor with the previous cursor position indicies, if they exist.
|
||||
// Initialize the cursor with the previous cursor position indices, if they exist.
|
||||
console.log("%s BaseView viewSection %s (%s) lastCursorPos %s", this._debugName, this.viewSection.getRowId(),
|
||||
this.viewSection.table().tableId(), JSON.stringify(this.viewSection.lastCursorPos));
|
||||
this.cursor = this.autoDispose(Cursor.create(null, this, this.viewSection.lastCursorPos));
|
||||
|
@ -97,7 +97,7 @@ export class ColumnTransform extends Disposable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper called by contructor to prepare the column transform.
|
||||
* Helper called by constructor to prepare the column transform.
|
||||
* @param {String} colType: A pure or complete type for the transformed column.
|
||||
*/
|
||||
public async prepare(optColType?: string) {
|
||||
@ -156,7 +156,7 @@ export class ColumnTransform extends Disposable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the tranform column and returns its colRef. May be overridden by derived classes to create
|
||||
* Adds the transform column and returns its colRef. May be overridden by derived classes to create
|
||||
* differently-prepared transform columns.
|
||||
* @param {String} colType: A pure or complete type for the transformed column.
|
||||
*/
|
||||
|
@ -77,7 +77,7 @@ export class Drafts extends Disposable {
|
||||
editor.setState(draft.state);
|
||||
}
|
||||
// We don't need the draft any more.
|
||||
// If user presses escape one more time it will be crated
|
||||
// If user presses escape one more time it will be created
|
||||
// once again
|
||||
storage.clear();
|
||||
// Close the notification
|
||||
|
@ -610,7 +610,7 @@ GridView.prototype.assignCursor = function(elem, elemType) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Schedules cursor assignement to happen at end of tick. Calling `preventAssignCursor()` before
|
||||
* Schedules cursor assignment to happen at end of tick. Calling `preventAssignCursor()` before
|
||||
* prevents assignment to happen. This was added to prevent cursor assignment on a `context click`
|
||||
* on a cell that is already selected.
|
||||
*/
|
||||
|
@ -351,7 +351,7 @@ export class Importer extends DisposableWithEvents {
|
||||
destTableId,
|
||||
destCols: transformFields.map<TransformColumn>((field) => ({
|
||||
label: field.label(),
|
||||
colId: destTableId ? field.colId() : null, // if inserting into new table, colId isnt defined
|
||||
colId: destTableId ? field.colId() : null, // if inserting into new table, colId isn't defined
|
||||
type: field.column().type(),
|
||||
formula: field.column().formula()
|
||||
})),
|
||||
|
@ -215,7 +215,7 @@ RecordLayout.prototype.saveLayoutSpec = async function(layoutSpec) {
|
||||
var addedPositions = [];
|
||||
|
||||
// Recursively process all layoutBoxes in the spec. Sets up bookkeeping arrays for
|
||||
// exisiting fields and added fields for new/hidden cols from which the action bundle will
|
||||
// existing fields and added fields for new/hidden cols from which the action bundle will
|
||||
// be created.
|
||||
function processBox(spec) {
|
||||
// "empty" is a temporary placeholder used by LayoutEditor, and not a valid leaf.
|
||||
|
@ -3,7 +3,7 @@
|
||||
* of a plugin.
|
||||
*
|
||||
* A plugin's safeBrowser component is made of one main entry point (the javascript files declares
|
||||
* in the manifest), html files and any ressources included by the html files (css, scripts, images
|
||||
* in the manifest), html files and any resources included by the html files (css, scripts, images
|
||||
* ...). The main script is the main entry point which uses the Grist API to render the views,
|
||||
* communicate with them en dispose them.
|
||||
*
|
||||
@ -18,13 +18,13 @@
|
||||
*
|
||||
* The grist API available to safeBrowser components is implemented in `app/plugin/PluginImpl.ts`.
|
||||
*
|
||||
* All the safeBrowser's component ressources, including the main script, the html files and any
|
||||
* other ressources needed by the views, should be placed within one plugins' subfolder, and Grist
|
||||
* All the safeBrowser's component resources, including the main script, the html files and any
|
||||
* other resources needed by the views, should be placed within one plugins' subfolder, and Grist
|
||||
* should serve only this folder. However, this is not yet implemented and is left as a TODO, as of
|
||||
* now the whole plugin's folder is served.
|
||||
*
|
||||
*/
|
||||
// Todo: plugin ressources should not be made available on the server by default, but only after
|
||||
// Todo: plugin resources should not be made available on the server by default, but only after
|
||||
// activation.
|
||||
|
||||
// tslint:disable:max-classes-per-file
|
||||
@ -131,7 +131,7 @@ export class SafeBrowser extends BaseComponent {
|
||||
// it's ok to leave it for now: (1) fixing this would require (yet) another refactoring of
|
||||
// SafeBrowser and (2) at this point it is not sure wether we want to keep `render()` in the
|
||||
// future (we could as well directly register contribution using files directly in the
|
||||
// manifest), and (3) plugins are only developped by us, we only have to remember that using
|
||||
// manifest), and (3) plugins are only developed by us, we only have to remember that using
|
||||
// `render()` is only supported from within the main process (which cover all our use cases so
|
||||
// far).
|
||||
}
|
||||
|
2
app/client/lib/dispose.d.ts
vendored
2
app/client/lib/dispose.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
// TODO: add remaining Disposable methode
|
||||
// TODO: add remaining Disposable method
|
||||
export abstract class Disposable {
|
||||
public static create<T extends new (...args: any[]) => any>(
|
||||
this: T, ...args: ConstructorParameters<T>): InstanceType<T>;
|
||||
|
@ -146,7 +146,7 @@ export async function uploadFiles(
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches ressource from a url and returns an UploadResult. Tries to fetch from the client and
|
||||
* Fetches resource from a url and returns an UploadResult. Tries to fetch from the client and
|
||||
* upload the file to the server. If unsuccessful, tries to fetch directly from the server. In both
|
||||
* case, it guesses the name of the file based on the response's content-type and the url.
|
||||
*/
|
||||
|
@ -34,7 +34,7 @@ export class DocData extends BaseDocData {
|
||||
|
||||
/**
|
||||
* Constructor for DocData.
|
||||
* @param {Object} docComm: A map of server methods availble on this document.
|
||||
* @param {Object} docComm: A map of server methods available on this document.
|
||||
* @param {Object} metaTableData: A map from tableId to table data, presented as an action,
|
||||
* equivalent to BulkAddRecord, i.e. ["TableData", tableId, rowIds, columnValues].
|
||||
*/
|
||||
|
@ -74,7 +74,7 @@ function getRecords(table: TreeTableData) {
|
||||
return fixIndents(records);
|
||||
}
|
||||
|
||||
// The fixIndents function returns a copy of records with the garantee the .indentation starts at 0
|
||||
// The fixIndents function returns a copy of records with the guarantee the .indentation starts at 0
|
||||
// and can only increase one step at a time (note that it is however permitted to decrease several
|
||||
// level at a time). This is useful to build a model for the tree view.
|
||||
export function fixIndents(records: TreeRecord[]) {
|
||||
|
@ -20,7 +20,7 @@ export class UserError extends Error {
|
||||
}
|
||||
|
||||
/**
|
||||
* This error causes Notifer to show the message with an upgrade link.
|
||||
* This error causes Notifier to show the message with an upgrade link.
|
||||
*/
|
||||
export class NeedUpgradeError extends Error {
|
||||
public name: string = 'NeedUpgradeError';
|
||||
|
@ -20,7 +20,7 @@ const testId = makeTestId('test-apikey-');
|
||||
* ApiKey component shows an api key with controls to change it. Expects `options.apiKey` the api
|
||||
* key and shows it if value is truthy along with a 'Delete' button that triggers the
|
||||
* `options.onDelete` callback. When `options.apiKey` is falsy, hides it and show a 'Create' button
|
||||
* that triggers the `options.onCreate` callback. It is the responsability of the caller to update
|
||||
* that triggers the `options.onCreate` callback. It is the responsibility of the caller to update
|
||||
* the `options.apiKey` to its new value.
|
||||
*/
|
||||
export class ApiKey extends Disposable {
|
||||
|
@ -56,7 +56,7 @@ function createMainPage(appModel: AppModel, appObj: App) {
|
||||
} else if (err && (err.status === 401 || err.status === 403)) {
|
||||
// Generally give access denied error.
|
||||
// The exception is for document pages, where we want to allow access to documents
|
||||
// shared publically without being shared specifically with the current user.
|
||||
// shared publicly without being shared specifically with the current user.
|
||||
if (appModel.pageType.get() !== 'doc') {
|
||||
return createForbiddenPage(appModel);
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ export function columnFilterMenu(owner: IDisposableOwner, opts: IFilterMenuOptio
|
||||
* On user clicks, if checkbox is checked, it does uncheck all the values, and if the
|
||||
* `switchFilterType` is true it also converts the filter into an inclusion filter. But if the
|
||||
* checkbox is unchecked, or in the Indeterminate state, it does check all the values, and if the
|
||||
* `switchFilterType` is true it also converts the filter into an exlusion filter.
|
||||
* `switchFilterType` is true it also converts the filter into an exclusion filter.
|
||||
*/
|
||||
function buildSummary(label: string|Computed<string>, values: Array<[CellValue, IFilterCount]>,
|
||||
switchFilterType: boolean, model: ColumnFilterMenuModel) {
|
||||
|
@ -53,7 +53,7 @@ export function openFilePicker(options: FileDialogOptions): Promise<File[]> {
|
||||
|
||||
/**
|
||||
* Opens the file picker dialog. If files are selected, calls the provided callback.
|
||||
* If no files are seleced, will call the callback with an empty list if possible, or more
|
||||
* If no files are selected, will call the callback with an empty list if possible, or more
|
||||
* typically not call it at all.
|
||||
*/
|
||||
export function open(options: FileDialogOptions, callback: FilesCB): void {
|
||||
|
@ -194,7 +194,7 @@ export class MFAConfig extends Disposable {
|
||||
return [
|
||||
this._buildSecurityVerificationForm(ctl, {onSuccess: async (hadSecondStep) => {
|
||||
/**
|
||||
* If method was unspecified, but second step verification occured, we know that
|
||||
* If method was unspecified, but second step verification occurred, we know that
|
||||
* the client doesn't have up-to-date 2FA preferences. Close the modal, and force
|
||||
* a refresh of UserMFAPreferences, which should cause the correct buttons to be
|
||||
* rendered once preferences are loaded.
|
||||
|
@ -90,7 +90,7 @@ function allowOtherOrgs(doc: Document, app: AppModel): boolean {
|
||||
|
||||
|
||||
/**
|
||||
* Ask user for the desination and new name, and make a copy of the doc using those.
|
||||
* Ask user for the destination and new name, and make a copy of the doc using those.
|
||||
*/
|
||||
export async function makeCopy(doc: Document, app: AppModel, modalTitle: string): Promise<void> {
|
||||
if (!app.currentValidUser) {
|
||||
|
@ -75,7 +75,7 @@ function buildDomFromTable(pagesTable: MetaTableModel<PageRec>, activeDoc: Grist
|
||||
}
|
||||
|
||||
// if user removes a primary view, let's confirm first, because this will remove the
|
||||
// corresponsing table and also all pages that are using this table.
|
||||
// corresponding table and also all pages that are using this table.
|
||||
// TODO: once we have raw table view, removing page should remove just the view (not the
|
||||
// table), but for now this is the only way to remove a table in the newui.
|
||||
actions.onRemove = () => confirmModal(
|
||||
|
@ -91,7 +91,7 @@ const testId = makeTestId('test-treeview-');
|
||||
* item and by highlighting its parent. In order to ensure data consistency, the component prevents
|
||||
* dropping an item within its own children. If the cursor leaves the component during a drag, all
|
||||
* such visual artifact (handle, target and target's parent) are hidden, but if the cursor re-enter
|
||||
* the componet without releasing the mouse, they will show again allowing user to resume dragging.
|
||||
* the component without releasing the mouse, they will show again allowing user to resume dragging.
|
||||
*/
|
||||
// note to self: in the future the model will be updated by the server, which could cause conflicts
|
||||
// if the user is dragging at the same time. It could be simpler to freeze the model and to differ
|
||||
@ -125,7 +125,7 @@ export class TreeViewComponent extends Disposable {
|
||||
|
||||
// While building dom we add listeners to the children of all tree nodes to watch for changes
|
||||
// and call this._update. Hence, repeated calls to this._update is likely to add or remove
|
||||
// listeners to the observable that triggered the udpate which is not supported by grainjs and
|
||||
// listeners to the observable that triggered the update which is not supported by grainjs and
|
||||
// could fail (possibly infinite loop). Debounce allows for several change to resolve to a
|
||||
// single update.
|
||||
this._update = debounce(this._update.bind(this), 0, {leading: false});
|
||||
@ -230,7 +230,7 @@ export class TreeViewComponent extends Disposable {
|
||||
|
||||
// Update this._childrenDom with the content of the new tree. Its rebuilds entirely the tree of
|
||||
// items and reuses dom from the old content for each item that were already part of the old
|
||||
// tree. Then takes care of disposing dom for thoses items that were removed from the old tree.
|
||||
// tree. Then takes care of disposing dom for those items that were removed from the old tree.
|
||||
private _update() {
|
||||
this._childrenDom.set(this._buildChildren(this._model.get().children(), 0));
|
||||
|
||||
|
@ -423,7 +423,7 @@ function buildCheckbox(...args: IDomArgs<HTMLInputElement>) {
|
||||
);
|
||||
}
|
||||
|
||||
// helper to find checkboxes withing a draggable list. This assumes that checkboxes are the only
|
||||
// helper to find checkboxes within a draggable list. This assumes that checkboxes are the only
|
||||
// <input> element in draggableElement.
|
||||
function findCheckboxes(draggableElement: Element): NodeListOf<HTMLInputElement> {
|
||||
return draggableElement.querySelectorAll<HTMLInputElement>('input');
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* CSS Variables. To use in your web appication, add `cssRootVars` to the class list for your app's
|
||||
* CSS Variables. To use in your web application, add `cssRootVars` to the class list for your app's
|
||||
* root node, typically `<body>`.
|
||||
*
|
||||
* The fonts used attempt to default to system fonts as described here:
|
||||
|
@ -20,7 +20,7 @@ const cssWrapper = styled('div', `
|
||||
`);
|
||||
|
||||
export const cssLabelText = styled(rawTextInput, `
|
||||
/* Reset apperance */
|
||||
/* Reset appearance */
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
padding: 0;
|
||||
|
@ -22,7 +22,7 @@ export interface IModalControl {
|
||||
// Returns true if closed, false if closing was prevented.
|
||||
closeAndWait(): Promise<boolean>;
|
||||
|
||||
// Prevents closing, if close has been called ans is pending. No-op otherwise.
|
||||
// Prevents closing, if close has been called and is pending. No-op otherwise.
|
||||
preventClose(): void;
|
||||
|
||||
// Wraps the passed-in function, so that closing is delayed while the function is running. If
|
||||
|
@ -64,7 +64,7 @@ export function buildPageDom(name: Observable<string>, actions: PageActions, ...
|
||||
dom.on('click', (ev) => { ev.stopPropagation(); ev.preventDefault(); })
|
||||
),
|
||||
// Note that we don't pass extra args when renaming is on, because they usually includes
|
||||
// mouse event handlers interferring with input editor and yields wrong behavior on
|
||||
// mouse event handlers interfering with input editor and yields wrong behavior on
|
||||
// firefox.
|
||||
) :
|
||||
cssPageItem(
|
||||
|
@ -35,7 +35,7 @@ BaseEditor.prototype.getCellValue = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Used if an editor needs preform any actions before a save
|
||||
* Used if an editor needs perform any actions before a save
|
||||
*/
|
||||
BaseEditor.prototype.prepForSave = function() {
|
||||
// No-op by default.
|
||||
|
@ -430,9 +430,9 @@ export function openFormulaEditor(options: {
|
||||
editor.attach(refElem);
|
||||
|
||||
// When formula is empty enter formula-editing mode (highlight formula icons; click on a column inserts its ID).
|
||||
// This function is used for primarily for switching between diffrent column behaviors, so we want to enter full
|
||||
// This function is used for primarily for switching between different column behaviors, so we want to enter full
|
||||
// edit mode right away.
|
||||
// TODO: consider converting it to parameter, when this will be used in diffrent scenarios.
|
||||
// TODO: consider converting it to parameter, when this will be used in different scenarios.
|
||||
if (!column.formula()) {
|
||||
field.editingFormula(true);
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ export abstract class NewBaseEditor extends Disposable {
|
||||
public abstract getCellValue(): CellValue;
|
||||
|
||||
/**
|
||||
* Used if an editor needs preform any actions before a save
|
||||
* Used if an editor needs perform any actions before a save
|
||||
*/
|
||||
public prepForSave(): void | Promise<void> {
|
||||
// No-op by default.
|
||||
|
@ -28,7 +28,7 @@ import toPairs = require('lodash/toPairs');
|
||||
* removal of a table (or column) as the special name pair [finalName, null].
|
||||
*
|
||||
* An ActionSummary contains two fields:
|
||||
* - tableRenames: a list of table name changes (incuding addition/removal).
|
||||
* - tableRenames: a list of table name changes (including addition/removal).
|
||||
* - tableDeltas: a dictionary of changes within a table.
|
||||
*
|
||||
* The key of the tableDeltas dictionary is the name of a table at the end of the
|
||||
@ -45,7 +45,7 @@ import toPairs = require('lodash/toPairs');
|
||||
*
|
||||
* The changes within a table are represented as a TableDelta, which has the following
|
||||
* fields:
|
||||
* - columnRenames: a list of column name changes (incuding addition/removal).
|
||||
* - columnRenames: a list of column name changes (including addition/removal).
|
||||
* - columnDeltas: a dictionary of changes within a column.
|
||||
* - updateRows, removeRows, addRows: lists of affected rows.
|
||||
*
|
||||
|
@ -58,7 +58,7 @@ export interface ImportResult {
|
||||
|
||||
export interface ImportTableResult {
|
||||
hiddenTableId: string;
|
||||
uploadFileIndex: number; // Index into upload.files array, for the file reponsible for this table.
|
||||
uploadFileIndex: number; // Index into upload.files array, for the file responsible for this table.
|
||||
origTableName: string;
|
||||
transformSectionRef: number;
|
||||
destTableId: string|null;
|
||||
|
@ -132,7 +132,7 @@ BinaryIndexedTree.prototype.fillFromCumulative = function(cumulValues) {
|
||||
|
||||
|
||||
/**
|
||||
* Creates a tree from an array of invididual values.
|
||||
* Creates a tree from an array of individual values.
|
||||
* Takes time linear in the size of the array.
|
||||
* @param {Array<number>} - array with each element containing the value to insert.
|
||||
*/
|
||||
|
@ -2,7 +2,7 @@
|
||||
* InactivityTimer allows to set a function that executes after a certain time of
|
||||
* inactivity. Activities can be of two kinds: synchronous or asynchronous. Asynchronous activities,
|
||||
* are handle with the `disableUntiFinish` method that takes in a Promise and makes sure that the
|
||||
* timer does not start before the promise resolves. Synchroneous activities are monitored with the
|
||||
* timer does not start before the promise resolves. Synchronous activities are monitored with the
|
||||
* `ping` method which resets the timer if called during inactivity.
|
||||
*
|
||||
* Timer won't start before any activity happens, but you may simply call ping() after construction
|
||||
|
@ -12,7 +12,7 @@ import {RenderOptions, RenderTarget} from 'app/plugin/RenderOptions';
|
||||
export type ComponentKind = "safeBrowser" | "safePython" | "unsafeNode";
|
||||
|
||||
// Describes a function that appends some html content to `containerElement` given some
|
||||
// options. Usefull for provided by a plugin.
|
||||
// options. Useful for provided by a plugin.
|
||||
export type TargetRenderFunc = (containerElement: HTMLElement, options?: RenderOptions) => void;
|
||||
|
||||
/**
|
||||
@ -93,7 +93,7 @@ export abstract class BaseComponent implements IForwarderDest {
|
||||
* Node Implementation for the PluginElement interface. A PluginInstance take care of activation of
|
||||
* the the plugins's components (activating, timing and deactivating), and create the api's for each contributions.
|
||||
*
|
||||
* Do not try to instanciate yourself, PluginManager does it for you. Instead use the
|
||||
* Do not try to instantiate yourself, PluginManager does it for you. Instead use the
|
||||
* PluginManager.getPlugin(id) method that get instances for you.
|
||||
*
|
||||
*/
|
||||
|
@ -64,7 +64,7 @@ export function typedCompare(val1: any, val2: any): number {
|
||||
if ((result = nativeCompare(type1 = typeof val1, typeof val2)) !== 0) {
|
||||
return result;
|
||||
}
|
||||
// We need to worry about Array comparisons because formulas returing Any may return null or
|
||||
// We need to worry about Array comparisons because formulas returning Any may return null or
|
||||
// object values represented as arrays (e.g. ['D', ...] for dates). Comparing those without
|
||||
// distinguishing types would break the sort. Also, arrays need a special comparator.
|
||||
if (type1 === 'object') {
|
||||
|
@ -40,7 +40,7 @@ function hasNestedObjects(value: any[]) {
|
||||
* Formats a decoded Grist value for displaying it. For top-level values, formats them the way we
|
||||
* like to see them in a cell or in, say, CSV export.
|
||||
* For top-level lists containing only simple values like strings and dates, formats them as a CSV row.
|
||||
* Nested lists and objects are formatted slighly differently, with quoted strings and ISO format for dates.
|
||||
* Nested lists and objects are formatted slightly differently, with quoted strings and ISO format for dates.
|
||||
*/
|
||||
export function formatDecoded(value: unknown, isTopLevel: boolean = true): string {
|
||||
if (typeof value === 'object' && value) {
|
||||
|
@ -45,7 +45,7 @@ export interface GristAPI {
|
||||
/**
|
||||
* Render the file at `path` into the `target` location in Grist. `path` must be relative to the
|
||||
* root of the plugin's directory and point to an html that is contained within the plugin's
|
||||
* directory. `target` is a predifined location of the Grist UI, it could be `fullscreen` or
|
||||
* directory. `target` is a predefined location of the Grist UI, it could be `fullscreen` or
|
||||
* identifier for an inline target. Grist provides inline target identifiers in certain call
|
||||
* plugins. E.g. ImportSourceAPI.getImportSource is given a target identifier to allow rende UI
|
||||
* inline in the import dialog. Returns the procId which can be used to dispose the view.
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Provide a way to acess grist for iframe, web worker (which runs the main safeBrowser script) and
|
||||
// Provide a way to access grist for iframe, web worker (which runs the main safeBrowser script) and
|
||||
// unsafeNode. WebView should work the same way as iframe, grist is exposed just the same way and
|
||||
// necessary api is exposed using preload script. Here we bootstrap from channel capabilities to key
|
||||
// parts of the grist API.
|
||||
@ -230,7 +230,7 @@ export function onOptions(callback: (options: any, settings: InteractionOptions)
|
||||
*
|
||||
*/
|
||||
export async function addImporter(name: string, path: string, mode: 'fullscreen' | 'inline', options?: RenderOptions) {
|
||||
// checker is omitted for implementation because call was alredy checked by grist.
|
||||
// checker is omitted for implementation because call was already checked by grist.
|
||||
rpc.registerImpl<InternalImportSourceAPI>(name, {
|
||||
async getImportSource(target: RenderTarget): Promise<ImportSource|undefined> {
|
||||
const procId = await api.render(path, mode === 'inline' ? target : 'fullscreen', options);
|
||||
@ -308,7 +308,7 @@ if (typeof window !== 'undefined') {
|
||||
process.on('disconnect', () => { process.exit(0); });
|
||||
} else {
|
||||
// Not a recognized environment, perhaps plain nodejs run independently of Grist, or tests
|
||||
// running under mocha. For now, we only provide a disfunctional implementation. It allows
|
||||
// running under mocha. For now, we only provide a dysfunctional implementation. It allows
|
||||
// plugins to call methods like registerFunction() without failing, so that plugin code may be
|
||||
// imported, but the methods don't do anything useful.
|
||||
rpc.setSendMessage((data) => { return; });
|
||||
|
@ -453,7 +453,7 @@ export class ActionHistoryImpl implements ActionHistory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the most recent action row from the history, orderd with earlier actions first.
|
||||
* Fetches the most recent action row from the history, ordered with earlier actions first.
|
||||
* If `maxActions` is supplied, at most that number of actions are returned.
|
||||
*/
|
||||
private async _getRecentActionRows(maxActions: number|undefined,
|
||||
|
@ -19,7 +19,7 @@ import values = require('lodash/values');
|
||||
const MAXIMUM_INLINE_ROWS = 10;
|
||||
|
||||
/**
|
||||
* Options when producing an action sumary.
|
||||
* Options when producing an action summary.
|
||||
*/
|
||||
export interface ActionSummaryOptions {
|
||||
maximumInlineRows?: number; // Overrides the maximum number of rows in a
|
||||
@ -309,7 +309,7 @@ function renameAndDelete<T>(entries: {[name: string]: T}, dead: Set<string>,
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply planned name changes to a pair of entries, and return a merged entry encorporating
|
||||
* Apply planned name changes to a pair of entries, and return a merged entry incorporating
|
||||
* their composition.
|
||||
*
|
||||
* @param names: the planned name changes as calculated by planNameMerge()
|
||||
|
@ -349,7 +349,7 @@ export class ActiveDocImport {
|
||||
hiddenTableId: createdTableId, // TODO: rename thing?
|
||||
uploadFileIndex,
|
||||
origTableName,
|
||||
transformSectionRef, // TODO: this shouldnt always be needed, and we only get it if genimporttransform
|
||||
transformSectionRef, // TODO: this shouldn't always be needed, and we only get it if genimporttransform
|
||||
destTableId
|
||||
});
|
||||
}
|
||||
|
@ -482,7 +482,7 @@ export function assertAccess(
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull out headers to pass along to a proxied service. Focussed primarily on
|
||||
* Pull out headers to pass along to a proxied service. Focused primarily on
|
||||
* authentication.
|
||||
*/
|
||||
export function getTransitiveHeaders(req: Request): {[key: string]: string} {
|
||||
|
@ -129,7 +129,7 @@ export function linkOrgWithEmail(session: SessionObj, email: string, org: string
|
||||
*
|
||||
* This is a view of the session object, for a single organization (the "scope").
|
||||
*
|
||||
* Local caching is disabled in an enviroment where there is a home server (or we are
|
||||
* Local caching is disabled in an environment where there is a home server (or we are
|
||||
* the home server). In hosted Grist, per-instance caching would be a problem.
|
||||
*
|
||||
* We retain local caching for situations with a single server - especially electron.
|
||||
|
@ -51,7 +51,7 @@ class GristDocAPIImpl implements GristDocAPI {
|
||||
/**
|
||||
* DocPluginManager manages plugins for a document.
|
||||
*
|
||||
* DocPluginManager instanciates asynchronously. Wait for the `ready` to resolve before using any
|
||||
* DocPluginManager instantiates asynchronously. Wait for the `ready` to resolve before using any
|
||||
* plugin.
|
||||
*
|
||||
*/
|
||||
|
@ -85,7 +85,7 @@ export class DocSnapshotPruner {
|
||||
* steady state).
|
||||
*
|
||||
* The list of versions (with metadata) for a document is itself stored in S3. This isn't
|
||||
* ideal since we cannnot simply append a new version to the list without rewriting it in full.
|
||||
* ideal since we cannot simply append a new version to the list without rewriting it in full.
|
||||
* But the alternatives have more serious problems, and this way folds quite well into the
|
||||
* existing pruning setup.
|
||||
* - Storing in db would mean we'd need sharding sooner than otherwise
|
||||
|
@ -678,7 +678,7 @@ export class DocStorage implements ISQLiteDB {
|
||||
*/
|
||||
public _initDB(): Promise<void> {
|
||||
// Set options for speed across multiple OSes/Filesystems.
|
||||
// WAL is fast and safe (guarantees consistency accross crashes), but has disadvantages
|
||||
// WAL is fast and safe (guarantees consistency across crashes), but has disadvantages
|
||||
// including generating unwanted extra files that can be tricky to deal with in renaming, etc
|
||||
// the options for WAL are commented out
|
||||
// Setting synchronous to OFF is the fastest method, but is not as safe, and could lead to
|
||||
|
@ -57,7 +57,7 @@ export interface IDocWorkerMap extends IPermitStores, IElectionStore, IChecksumS
|
||||
setWorkerAvailability(workerId: string, available: boolean): Promise<void>;
|
||||
|
||||
// Releases doc from worker, freeing it to be assigned elsewhere.
|
||||
// Assigments should only be released for workers that are now unavailable.
|
||||
// Assignments should only be released for workers that are now unavailable.
|
||||
releaseAssignment(workerId: string, docId: string): Promise<void>;
|
||||
|
||||
// Get all assignments for a worker. Should only be queried for a worker that
|
||||
|
@ -134,7 +134,7 @@ export function expandQuery(iquery: ServerQuery, docData: DocData, onDemandFormu
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a query that relates two homogenous tables sharing a common set of columns,
|
||||
* Build a query that relates two homogeneous tables sharing a common set of columns,
|
||||
* returning rows that exist in both tables (if they have differences), and rows from
|
||||
* `leftTableId` that don't exist in `rightTableId`.
|
||||
*
|
||||
|
@ -208,7 +208,7 @@ export class ChecksummedExternalStorage implements ExternalStorage {
|
||||
|
||||
/**
|
||||
* We may want to download material from one key and henceforth treat it as another
|
||||
* key (specifically for forking a document). Since this class crossreferences the
|
||||
* key (specifically for forking a document). Since this class cross-references the
|
||||
* key in the external store with other consistent stores, it needs to know we are
|
||||
* doing that. So we add a downloadTo variant that takes before and after keys.
|
||||
*/
|
||||
|
@ -1070,7 +1070,7 @@ export class FlexServer implements GristServer {
|
||||
const scope = addPermit(getScope(mreq), this._dbManager.getSupportUserId(), {org: orgDomain});
|
||||
const query = await this._dbManager.getOrg(scope, orgDomain);
|
||||
const org = this._dbManager.unwrapQueryResult(query);
|
||||
// This page isn't availabe for personal site.
|
||||
// This page isn't available for personal site.
|
||||
if (org.owner) {
|
||||
return this._sendAppPage(req, resp, {path: 'error.html', status: 404, config: {errPage: 'not-found'}});
|
||||
}
|
||||
|
@ -373,7 +373,7 @@ export class GranularAccess implements GranularAccessForBundle {
|
||||
|
||||
/**
|
||||
* Check whether an ActionGroup can be sent to the client. TODO: in future, we'll want
|
||||
* to filter acceptible parts of ActionGroup, rather than denying entirely.
|
||||
* to filter acceptable parts of ActionGroup, rather than denying entirely.
|
||||
*/
|
||||
public async allowActionGroup(docSession: OptDocSession, actionGroup: ActionGroup): Promise<boolean> {
|
||||
return this.canReadEverything(docSession);
|
||||
|
@ -19,7 +19,7 @@ export class HostedMetadataManager {
|
||||
// Callback for next opportunity to push changes.
|
||||
private _timeout: any = null;
|
||||
|
||||
// Mantains the update Promise to wait on it if the class is closing.
|
||||
// Maintains the update Promise to wait on it if the class is closing.
|
||||
private _push: Promise<any>|null;
|
||||
|
||||
/**
|
||||
@ -65,7 +65,7 @@ export class HostedMetadataManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Push all metadata updates to the databse.
|
||||
* Push all metadata updates to the database.
|
||||
*/
|
||||
private _update(): void {
|
||||
if (this._push) { return; }
|
||||
|
@ -350,7 +350,7 @@ const spawners = {
|
||||
* - GRIST_SANDBOX_FLAVOR: should be one of the spawners (pynbox, unsandboxed, docker,
|
||||
* gvisor, macSandboxExec)
|
||||
* - GRIST_SANDBOX: a program or image name to run as the sandbox. Not needed for
|
||||
* pynbox (it is either built in or not avaiable). For unsandboxed, should be an
|
||||
* pynbox (it is either built in or not available). For unsandboxed, should be an
|
||||
* absolute path to python within a virtualenv with all requirements installed.
|
||||
* For docker, it should be `grist-docker-sandbox` (an image built via makefile
|
||||
* in `sandbox/docker`) or a derived image. For gvisor, it should be the full path
|
||||
@ -743,7 +743,7 @@ function getWrappingEnv(options: ISandboxOptions) {
|
||||
* structure on the host rather than remapping, we can simplify nesting
|
||||
* wrappers, or cases where remapping isn't possible. It does leak the names
|
||||
* of the host directories though, and there could be silly complications if the
|
||||
* directories have spaces or other idiosyncracies. When committing to a sandbox
|
||||
* directories have spaces or other idiosyncrasies. When committing to a sandbox
|
||||
* technology, for stand-alone Grist, it would be worth rethinking this.
|
||||
*/
|
||||
function getAbsolutePaths(options: ISandboxOptions) {
|
||||
|
@ -66,7 +66,7 @@ export class PluginManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-load plugins (litterally re-run `loadPlugins`).
|
||||
* Re-load plugins (literally re-run `loadPlugins`).
|
||||
*/
|
||||
// TODO: it's not clear right now what we do on reload. Do we deactivate plugins that were removed
|
||||
// from the fs? Do we update plugins that have changed on the fs ?
|
||||
|
@ -114,7 +114,7 @@ export type DBFunc = (db: SQLiteDB) => Promise<void>;
|
||||
export enum OpenMode {
|
||||
OPEN_CREATE, // Open DB or create if doesn't exist (the default mode for sqlite3 module)
|
||||
OPEN_EXISTING, // Open DB or fail if doesn't exist
|
||||
OPEN_READONLY, // Open DB in read-only mode or fail if doens't exist.
|
||||
OPEN_READONLY, // Open DB in read-only mode or fail if doesn't exist.
|
||||
CREATE_EXCL, // Create new DB or fail if it already exists.
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ export class SamlConfig {
|
||||
if (state.action === 'login') {
|
||||
const samlUser = samlResponse.user;
|
||||
if (!samlUser || !samlUser.name_id) {
|
||||
log.warn(`SamlConfig: bad SAML reponse: ${JSON.stringify(samlUser)}`);
|
||||
log.warn(`SamlConfig: bad SAML response: ${JSON.stringify(samlUser)}`);
|
||||
throw new Error("Invalid user info in SAML response");
|
||||
}
|
||||
|
||||
@ -183,7 +183,7 @@ export class SamlConfig {
|
||||
// available. Otherwise we use user.attributes which has the form {Name: [Value]}.
|
||||
const fname = samlUser.given_name || samlUser.attributes.FirstName || '';
|
||||
const lname = samlUser.surname || samlUser.attributes.LastName || '';
|
||||
const email = samlUser.email || samlUser.nameId;
|
||||
const email = samlUser.email || samlUser.name_id;
|
||||
const profile = {
|
||||
email,
|
||||
name: `${fname} ${lname}`.trim(),
|
||||
|
@ -320,7 +320,7 @@ export class Sharing {
|
||||
isModification: sandboxActionBundle.stored.length > 0
|
||||
};
|
||||
} finally {
|
||||
// Make sure the bundle is marked as complete, even if some miscellaneous error occured.
|
||||
// Make sure the bundle is marked as complete, even if some miscellaneous error occurred.
|
||||
await accessControl.finishedBundle();
|
||||
}
|
||||
}
|
||||
|
@ -74,8 +74,8 @@ exports.createNumbered = createNumbered;
|
||||
/**
|
||||
* An easier-to-use alternative to createNumbered. Pass in a template string containing the
|
||||
* special token "{NUM}". It will first call creator() with "{NUM}" removed, then with "{NUM}"
|
||||
* replcaced by "-2", "-3", etc, until creator() succeeds, and will return the value for which it
|
||||
* suceeded.
|
||||
* replaced by "-2", "-3", etc, until creator() succeeds, and will return the value for which it
|
||||
* succeeded.
|
||||
*/
|
||||
function createNumberedTemplate(template, creator) {
|
||||
const [prefix, suffix] = template.split("{NUM}");
|
||||
|
@ -141,7 +141,7 @@ class Engine(object):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
# The document data, incuding logic (formulas), and metadata (tables prefixed with "_grist_").
|
||||
# The document data, including logic (formulas), and metadata (tables prefixed with "_grist_").
|
||||
self.tables = {} # Maps table IDs (or names) to Table objects.
|
||||
|
||||
# Schema contains information about tables and columns, needed in particular to generate the
|
||||
|
@ -152,7 +152,7 @@ class GenCode(object):
|
||||
return textbuilder.Combiner(parts)
|
||||
|
||||
def make_module(self, schema):
|
||||
"""Regenerates the code text and usercode module from upated document schema."""
|
||||
"""Regenerates the code text and usercode module from updated document schema."""
|
||||
# Collect summary tables to group them by source table.
|
||||
summary_tables = {}
|
||||
for table_info in six.itervalues(schema):
|
||||
|
@ -328,7 +328,7 @@ def _sliding_triplets(tokens):
|
||||
|
||||
|
||||
def _analyze_tokens(tokens):
|
||||
"""Analize each token and find out compatible types for it."""
|
||||
"""Analyze each token and find out compatible types for it."""
|
||||
for token, prev, nxt in _sliding_triplets(tokens):
|
||||
token.compatible_types = tuple([t for t in DATE_ELEMENTS if t[2](token.val, prev, nxt)])
|
||||
|
||||
|
@ -97,12 +97,12 @@ for typ in six.string_types:
|
||||
|
||||
SCHEMA = [{
|
||||
'name': 'includes',
|
||||
'label': 'Includes (list of tables seperated by semicolon)',
|
||||
'label': 'Includes (list of tables separated by semicolon)',
|
||||
'type': 'string',
|
||||
'visible': True
|
||||
}, {
|
||||
'name': 'excludes',
|
||||
'label': 'Excludes (list of tables seperated by semicolon)',
|
||||
'label': 'Excludes (list of tables separated by semicolon)',
|
||||
'type': 'string',
|
||||
'visible': True
|
||||
}]
|
||||
|
@ -111,7 +111,7 @@ def migration(schema_version, need_all_tables=False):
|
||||
is marked with need_all_tables=True, then the migration will be retried with all tables.
|
||||
|
||||
NOTE: new migrations should NOT set need_all_tables=True; it would require more work to process
|
||||
very large documents safely (incuding those containing on-demand tables).
|
||||
very large documents safely (including those containing on-demand tables).
|
||||
"""
|
||||
def add_migration(migration_func):
|
||||
migration_func.need_all_tables = need_all_tables
|
||||
|
@ -559,7 +559,7 @@ class Table(object):
|
||||
"""
|
||||
# We don't set up any dependencies, so it would be incorrect to use this from formulas.
|
||||
# We no longer assert, however, since such calls may still happen e.g. while applying
|
||||
# user-actions caused by formula side-effects (e.g. as trigged by lookupOrAddDerived())
|
||||
# user-actions caused by formula side-effects (e.g. as triggered by lookupOrAddDerived())
|
||||
if row_id not in self.row_ids:
|
||||
raise KeyError("'get_record' found no matching record")
|
||||
return self.Record(row_id, None)
|
||||
|
@ -3,7 +3,7 @@ import test_engine
|
||||
|
||||
class TestFindCol(test_engine.EngineTestCase):
|
||||
def test_find_col_from_values(self):
|
||||
# Test basic funtionality.
|
||||
# Test basic functionality.
|
||||
self.load_sample(testsamples.sample_students)
|
||||
self.assertEqual(self.engine.find_col_from_values(("Columbia", "Yale", "Eureka"), 0),
|
||||
[4, 10])
|
||||
|
@ -68,7 +68,7 @@ class TestRenames2(test_engine.EngineTestCase):
|
||||
[ 4, "CheckersA" , 5, 1 ],
|
||||
])
|
||||
|
||||
# This was just setpu. Now create some crazy formulas that overuse referenes in crazy ways.
|
||||
# This was just setpu. Now create some crazy formulas that overuse references in crazy ways.
|
||||
self.partner_names = textwrap.dedent(
|
||||
"""
|
||||
games = Entries.lookupRecords(person=$id).game
|
||||
|
@ -1047,7 +1047,7 @@ class UserActions(object):
|
||||
@override_action('BulkRemoveRecord', '_grist_Pages')
|
||||
def _removePageRecords(self, table_id, row_ids):
|
||||
"""
|
||||
Remove page records and for the those that have children, udpate the first child's indentation
|
||||
Remove page records and for the those that have children, update the first child's indentation
|
||||
so that it becomes the new parent. Note that this run a O(n) routine for each page to remove but
|
||||
it's ok considering that the list of _grist_Pages is not meant to grow that big.
|
||||
"""
|
||||
@ -1686,7 +1686,7 @@ class UserActions(object):
|
||||
# User actions on viewSections.
|
||||
#----------------------------------------
|
||||
|
||||
# TODO: Deprecated; This should no longer be an exposed action; it is superceded by
|
||||
# TODO: Deprecated; This should no longer be an exposed action; it is superseded by
|
||||
# CreateViewSection.
|
||||
@useraction
|
||||
def AddViewSection(self, title, view_section_type, view_row_id, table_id):
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
// This determines when a failed assertion shows a diff with details or
|
||||
// "expected [ Array(3) ] to deeply equal [ Array(3) ]".
|
||||
// Increase the threshhold since the default (of 40 characters) is often too low.
|
||||
// Increase the threshold since the default (of 40 characters) is often too low.
|
||||
// You can override it using CHAI_TRUNCATE_THRESHOLD env var; 0 disables it.
|
||||
require('chai').config.truncateThreshold = process.env.CHAI_TRUNCATE_THRESHOLD ?
|
||||
parseFloat(process.env.CHAI_TRUNCATE_THRESHOLD) : 200;
|
||||
|
@ -665,7 +665,7 @@ export async function importUrlDialog(url: string): Promise<void> {
|
||||
/**
|
||||
* Starts or resets the collections of UserActions. This should be followed some time later by
|
||||
* a call to userActionsVerify() to check which UserActions were sent to the server. If the
|
||||
* argumet is false, then stops the collection.
|
||||
* argument is false, then stops the collection.
|
||||
*/
|
||||
export function userActionsCollect(yesNo: boolean = true) {
|
||||
return driver.executeScript("window.gristApp.comm.userActionsCollect(arguments[0])", yesNo);
|
||||
|
Loading…
Reference in New Issue
Block a user