mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
Fixing all eslint's reported error
This commit is contained in:
parent
dcefd4a81b
commit
fd02a00a0e
@ -4,8 +4,8 @@
|
|||||||
!/test
|
!/test
|
||||||
!/plugins
|
!/plugins
|
||||||
!/buildtools
|
!/buildtools
|
||||||
|
!/stubs
|
||||||
!/.eslintrc.js
|
!/.eslintrc.js
|
||||||
|
|
||||||
# And exclude some things within those (generated files)
|
# And exclude some things within those (generated files)
|
||||||
/_build
|
|
||||||
/plugins/**/dist
|
/plugins/**/dist
|
||||||
|
@ -134,7 +134,7 @@ export class AccessRules extends Disposable {
|
|||||||
// there were only removals, then length will be reduced.
|
// there were only removals, then length will be reduced.
|
||||||
getChangedStatus(tableRules.length < this._ruleCollection.getAllTableIds().length),
|
getChangedStatus(tableRules.length < this._ruleCollection.getAllTableIds().length),
|
||||||
getChangedStatus(userAttr.length < this._ruleCollection.getUserAttributeRules().size),
|
getChangedStatus(userAttr.length < this._ruleCollection.getUserAttributeRules().size),
|
||||||
...tableRules.map(t => use(t.ruleStatus)),
|
...tableRules.map(tr => use(tr.ruleStatus)),
|
||||||
...userAttr.map(u => use(u.ruleStatus)),
|
...userAttr.map(u => use(u.ruleStatus)),
|
||||||
specialRules ? use(specialRules.ruleStatus) : RuleStatus.Unchanged,
|
specialRules ? use(specialRules.ruleStatus) : RuleStatus.Unchanged,
|
||||||
);
|
);
|
||||||
@ -239,7 +239,7 @@ export class AccessRules extends Disposable {
|
|||||||
const newResources: MetaRowRecord<'_grist_ACLResources'>[] = flatten(
|
const newResources: MetaRowRecord<'_grist_ACLResources'>[] = flatten(
|
||||||
[{tableId: '*', colIds: '*'}],
|
[{tableId: '*', colIds: '*'}],
|
||||||
this._specialRules.get()?.getResources() || [],
|
this._specialRules.get()?.getResources() || [],
|
||||||
...this._tableRules.get().map(t => t.getResources()))
|
...this._tableRules.get().map(tr => tr.getResources()))
|
||||||
.map(r => ({id: -1, ...r}));
|
.map(r => ({id: -1, ...r}));
|
||||||
|
|
||||||
// Prepare userActions and a mapping of serializedResource to rowIds.
|
// Prepare userActions and a mapping of serializedResource to rowIds.
|
||||||
@ -350,7 +350,7 @@ export class AccessRules extends Disposable {
|
|||||||
// synchronously, which prevents the menu from closing on click.
|
// synchronously, which prevents the menu from closing on click.
|
||||||
menuItemAsync(() => this._addTableRules(tableId),
|
menuItemAsync(() => this._addTableRules(tableId),
|
||||||
this.getTableTitle(tableId),
|
this.getTableTitle(tableId),
|
||||||
dom.cls('disabled', (use) => use(this._tableRules).some(t => t.tableId === tableId)),
|
dom.cls('disabled', (use) => use(this._tableRules).some(tr => tr.tableId === tableId)),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -442,7 +442,7 @@ export class AccessRules extends Disposable {
|
|||||||
*/
|
*/
|
||||||
public getRules(): RuleRec[] {
|
public getRules(): RuleRec[] {
|
||||||
return flatten(
|
return flatten(
|
||||||
...this._tableRules.get().map(t => t.getRules()),
|
...this._tableRules.get().map(tr => tr.getRules()),
|
||||||
this._specialRules.get()?.getRules() || [],
|
this._specialRules.get()?.getRules() || [],
|
||||||
this._docDefaultRuleSet.get()?.getRules('*') || []
|
this._docDefaultRuleSet.get()?.getRules('*') || []
|
||||||
);
|
);
|
||||||
@ -484,7 +484,7 @@ export class AccessRules extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _addTableRules(tableId: string) {
|
private _addTableRules(tableId: string) {
|
||||||
if (this._tableRules.get().some(t => t.tableId === tableId)) {
|
if (this._tableRules.get().some(tr => tr.tableId === tableId)) {
|
||||||
throw new Error(`Trying to add TableRules for existing table ${tableId}`);
|
throw new Error(`Trying to add TableRules for existing table ${tableId}`);
|
||||||
}
|
}
|
||||||
const defRuleSet: RuleSet = {tableId, colIds: '*', body: []};
|
const defRuleSet: RuleSet = {tableId, colIds: '*', body: []};
|
||||||
|
@ -239,7 +239,7 @@ export function buildUpgradeMessage(
|
|||||||
) {
|
) {
|
||||||
if (!canUpgrade) { return t("Contact the site owner to upgrade the plan to raise limits."); }
|
if (!canUpgrade) { return t("Contact the site owner to upgrade the plan to raise limits."); }
|
||||||
|
|
||||||
const upgradeLinkText = t("start your 30-day free trial of the Pro plan.")
|
const upgradeLinkText = t("start your 30-day free trial of the Pro plan.");
|
||||||
// TODO i18next
|
// TODO i18next
|
||||||
return [
|
return [
|
||||||
variant === 'short' ? null : t("For higher limits, "),
|
variant === 'short' ? null : t("For higher limits, "),
|
||||||
|
@ -986,7 +986,7 @@ export class GristDoc extends DisposableWithEvents {
|
|||||||
* Renames table. Method exposed primarily for tests.
|
* Renames table. Method exposed primarily for tests.
|
||||||
*/
|
*/
|
||||||
public async renameTable(tableId: string, newTableName: string) {
|
public async renameTable(tableId: string, newTableName: string) {
|
||||||
const tableRec = this.docModel.visibleTables.all().find(t => t.tableId.peek() === tableId);
|
const tableRec = this.docModel.visibleTables.all().find(tb => tb.tableId.peek() === tableId);
|
||||||
if (!tableRec) {
|
if (!tableRec) {
|
||||||
throw new UserError(`No table with id ${tableId}`);
|
throw new UserError(`No table with id ${tableId}`);
|
||||||
}
|
}
|
||||||
|
@ -380,7 +380,7 @@ export class Importer extends DisposableWithEvents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _getHiddenTableIds(): string[] {
|
private _getHiddenTableIds(): string[] {
|
||||||
return this._sourceInfoArray.get().map((t: SourceInfo) => t.hiddenTableId);
|
return this._sourceInfoArray.get().map((si: SourceInfo) => si.hiddenTableId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _reImport(upload: UploadResult) {
|
private async _reImport(upload: UploadResult) {
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import {computed, Computed, dom, DomElementArg, IDisposableOwner, Observable, styled} from "grainjs";
|
import {computed, Computed, dom, DomElementArg, IDisposableOwner, Observable, styled} from "grainjs";
|
||||||
import {cssModalBody, cssModalButtons, cssModalTitle, IModalControl, modal, cssAnimatedModal} from 'app/client/ui2018/modals';
|
import {cssAnimatedModal, cssModalBody, cssModalButtons, cssModalTitle,
|
||||||
|
IModalControl, modal} from 'app/client/ui2018/modals';
|
||||||
import {bigBasicButton, bigPrimaryButton} from 'app/client/ui2018/buttons';
|
import {bigBasicButton, bigPrimaryButton} from 'app/client/ui2018/buttons';
|
||||||
import {mediaXSmall, testId, theme, vars} from 'app/client/ui2018/cssVars';
|
import {mediaXSmall, testId, theme, vars} from 'app/client/ui2018/cssVars';
|
||||||
import {UserManagerModel, IOrgMemberSelectOption} from 'app/client/models/UserManagerModel';
|
import {IOrgMemberSelectOption, UserManagerModel} from 'app/client/models/UserManagerModel';
|
||||||
import {icon} from 'app/client/ui2018/icons';
|
import {icon} from 'app/client/ui2018/icons';
|
||||||
import {textarea} from "app/client/ui/inputs";
|
import {textarea} from "app/client/ui/inputs";
|
||||||
import {BasicRole, VIEWER, NonGuestRole, isBasicRole} from "app/common/roles";
|
import {BasicRole, isBasicRole, NonGuestRole, VIEWER} from "app/common/roles";
|
||||||
import {menu, menuItem} from 'app/client/ui2018/menus';
|
import {menu, menuItem} from 'app/client/ui2018/menus';
|
||||||
|
|
||||||
function parseEmailList(emailListRaw: string): Array<string> {
|
function parseEmailList(emailListRaw: string): Array<string> {
|
||||||
@ -28,9 +29,11 @@ export function buildMultiUserManagerModal(
|
|||||||
const emailListObs = Observable.create(owner, "");
|
const emailListObs = Observable.create(owner, "");
|
||||||
const rolesObs = Observable.create<BasicRole>(owner, VIEWER);
|
const rolesObs = Observable.create<BasicRole>(owner, VIEWER);
|
||||||
const isValidObs = Observable.create(owner, true);
|
const isValidObs = Observable.create(owner, true);
|
||||||
|
|
||||||
const enableAdd: Computed<boolean> = computed((use) => Boolean(use(emailListObs) && use(rolesObs) && use(isValidObs)));
|
const enableAdd: Computed<boolean> = computed(
|
||||||
|
(use) => Boolean(use(emailListObs) && use(rolesObs) && use(isValidObs))
|
||||||
|
);
|
||||||
|
|
||||||
const save = (ctl: IModalControl) => {
|
const save = (ctl: IModalControl) => {
|
||||||
const emailList = parseEmailList(emailListObs.get());
|
const emailList = parseEmailList(emailListObs.get());
|
||||||
const role = rolesObs.get();
|
const role = rolesObs.get();
|
||||||
@ -40,7 +43,7 @@ export function buildMultiUserManagerModal(
|
|||||||
emailList.forEach(email => onAdd(email, role));
|
emailList.forEach(email => onAdd(email, role));
|
||||||
ctl.close();
|
ctl.close();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return modal(ctl => [
|
return modal(ctl => [
|
||||||
{ style: 'padding: 0;' },
|
{ style: 'padding: 0;' },
|
||||||
@ -63,7 +66,7 @@ export function buildMultiUserManagerModal(
|
|||||||
{ style: 'margin: 32px 64px; display: flex;' },
|
{ style: 'margin: 32px 64px; display: flex;' },
|
||||||
bigPrimaryButton('Confirm',
|
bigPrimaryButton('Confirm',
|
||||||
dom.boolAttr('disabled', (use) => !use(enableAdd)),
|
dom.boolAttr('disabled', (use) => !use(enableAdd)),
|
||||||
dom.on('click', () => {save(ctl)}),
|
dom.on('click', () => { save(ctl); }),
|
||||||
testId('um-confirm')
|
testId('um-confirm')
|
||||||
),
|
),
|
||||||
bigBasicButton(
|
bigBasicButton(
|
||||||
|
@ -101,7 +101,7 @@ function domT(key: string, args: any, tImpl: typeof i18next.t) {
|
|||||||
// If there are any DomElements in args, handle it with missingInterpolationHandler.
|
// If there are any DomElements in args, handle it with missingInterpolationHandler.
|
||||||
const domElements = !args ? [] : Object.entries(args).filter(([_, value]) => isLikeDomContents(value));
|
const domElements = !args ? [] : Object.entries(args).filter(([_, value]) => isLikeDomContents(value));
|
||||||
if (!args || !domElements.length) {
|
if (!args || !domElements.length) {
|
||||||
return tImpl(key, args || undefined) as any;
|
return tImpl(key, args || undefined);
|
||||||
} else {
|
} else {
|
||||||
// Make a copy of the arguments, and remove any dom elements from it. It will instruct
|
// Make a copy of the arguments, and remove any dom elements from it. It will instruct
|
||||||
// i18next library to use `missingInterpolationHandler` handler.
|
// i18next library to use `missingInterpolationHandler` handler.
|
||||||
@ -171,5 +171,5 @@ export function makeT(scope: string, instance?: typeof i18next) {
|
|||||||
reportError(error);
|
reportError(error);
|
||||||
}
|
}
|
||||||
return domT(key, args, scopedResolver!);
|
return domT(key, args, scopedResolver!);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,9 @@ class ColumnPicker extends Disposable {
|
|||||||
properValue,
|
properValue,
|
||||||
options,
|
options,
|
||||||
{
|
{
|
||||||
defaultLabel: this._column.typeDesc != "any" ? t("Pick a {{columnType}} column", {"columnType": this._column.typeDesc}) : t("Pick a column")
|
defaultLabel: this._column.typeDesc != "any"
|
||||||
|
? t("Pick a {{columnType}} column", {"columnType": this._column.typeDesc})
|
||||||
|
: t("Pick a column")
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
testId('mapping-for-' + this._column.name),
|
testId('mapping-for-' + this._column.name),
|
||||||
@ -117,7 +119,11 @@ class ColumnListPicker extends Disposable {
|
|||||||
col.label.peek(),
|
col.label.peek(),
|
||||||
)),
|
)),
|
||||||
wrongTypeCount > 0 ? menuText(
|
wrongTypeCount > 0 ? menuText(
|
||||||
t("{{wrongTypeCount}} non-{{columnType}} columns are not shown", {wrongTypeCount, columnType: this._column.type.toLowerCase(), count: wrongTypeCount}),
|
t("{{wrongTypeCount}} non-{{columnType}} columns are not shown", {
|
||||||
|
wrongTypeCount,
|
||||||
|
columnType: this._column.type.toLowerCase(),
|
||||||
|
count: wrongTypeCount
|
||||||
|
}),
|
||||||
testId('map-message-' + this._column.name)
|
testId('map-message-' + this._column.name)
|
||||||
) : null
|
) : null
|
||||||
];
|
];
|
||||||
@ -371,8 +377,12 @@ export class CustomSectionConfig extends Disposable {
|
|||||||
}
|
}
|
||||||
switch(level) {
|
switch(level) {
|
||||||
case AccessLevel.none: return cssConfirmLine(t("Widget does not require any permissions."));
|
case AccessLevel.none: return cssConfirmLine(t("Widget does not require any permissions."));
|
||||||
case AccessLevel.read_table: return cssConfirmLine(t("Widget needs to {{read}} the current table.", {read: dom("b", "read")})); // TODO i18next
|
case AccessLevel.read_table:
|
||||||
case AccessLevel.full: return cssConfirmLine(t("Widget needs {{fullAccess}} to this document.", {fullAccess: dom("b", "full access")})); // TODO i18next
|
return cssConfirmLine(t("Widget needs to {{read}} the current table.", {read: dom("b", "read")}));
|
||||||
|
case AccessLevel.full:
|
||||||
|
return cssConfirmLine(t("Widget needs {{fullAccess}} to this document.", {
|
||||||
|
fullAccess: dom("b", "full access")
|
||||||
|
}));
|
||||||
default: throw new Error(`Unsupported ${level} access level`);
|
default: throw new Error(`Unsupported ${level} access level`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {makeT} from 'app/client/lib/localization'
|
import {makeT} from 'app/client/lib/localization';
|
||||||
|
|
||||||
const t = makeT('ExampleInfo');
|
const t = makeT('ExampleInfo');
|
||||||
|
|
||||||
|
@ -268,8 +268,8 @@ export class PageWidgetSelect extends Disposable {
|
|||||||
}) :
|
}) :
|
||||||
null;
|
null;
|
||||||
|
|
||||||
private _isNewTableDisabled = Computed.create(this, this._value.type, (use, t) => !isValidSelection(
|
private _isNewTableDisabled = Computed.create(this, this._value.type, (use, type) => !isValidSelection(
|
||||||
'New Table', t, this._options.isNewPage));
|
'New Table', type, this._options.isNewPage));
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _value: IWidgetValueObs,
|
private _value: IWidgetValueObs,
|
||||||
@ -399,8 +399,8 @@ export class PageWidgetSelect extends Disposable {
|
|||||||
this._value.summarize.set(true);
|
this._value.summarize.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _selectType(t: IWidgetType) {
|
private _selectType(type: IWidgetType) {
|
||||||
this._value.type.set(t);
|
this._value.type.set(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _selectTable(tid: TableId) {
|
private _selectTable(tid: TableId) {
|
||||||
|
@ -100,11 +100,11 @@ function removeView(activeDoc: GristDoc, viewId: number, pageName: string) {
|
|||||||
const removePage = () => [['RemoveRecord', '_grist_Views', viewId]];
|
const removePage = () => [['RemoveRecord', '_grist_Views', viewId]];
|
||||||
const removeAll = () => [
|
const removeAll = () => [
|
||||||
...removePage(),
|
...removePage(),
|
||||||
...notVisibleTables.map(t => ['RemoveTable', t.tableId.peek()])
|
...notVisibleTables.map(tb => ['RemoveTable', tb.tableId.peek()])
|
||||||
];
|
];
|
||||||
|
|
||||||
if (notVisibleTables.length) {
|
if (notVisibleTables.length) {
|
||||||
const tableNames = notVisibleTables.map(t => t.tableNameDef.peek());
|
const tableNames = notVisibleTables.map(tb => tb.tableNameDef.peek());
|
||||||
buildPrompt(tableNames, async (option) => {
|
buildPrompt(tableNames, async (option) => {
|
||||||
// Errors are handled in the dialog.
|
// Errors are handled in the dialog.
|
||||||
if (option === 'data') {
|
if (option === 'data') {
|
||||||
@ -174,7 +174,7 @@ function buildOption(value: Observable<RemoveOption>, id: RemoveOption, content:
|
|||||||
|
|
||||||
function buildWarning(tables: string[]) {
|
function buildWarning(tables: string[]) {
|
||||||
return cssWarning(
|
return cssWarning(
|
||||||
dom.forEach(tables, (t) => cssTableName(t, testId('table')))
|
dom.forEach(tables, (tb) => cssTableName(tb, testId('table')))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,8 +39,8 @@ import {icon} from 'app/client/ui2018/icons';
|
|||||||
import {cssLink} from 'app/client/ui2018/links';
|
import {cssLink} from 'app/client/ui2018/links';
|
||||||
import {loadingSpinner} from 'app/client/ui2018/loaders';
|
import {loadingSpinner} from 'app/client/ui2018/loaders';
|
||||||
import {menu, menuItem, menuText} from 'app/client/ui2018/menus';
|
import {menu, menuItem, menuText} from 'app/client/ui2018/menus';
|
||||||
import {confirmModal, cssModalBody, cssModalButtons, cssModalTitle, IModalControl,
|
import {confirmModal, cssAnimatedModal, cssModalBody, cssModalButtons, cssModalTitle,
|
||||||
modal, cssAnimatedModal} from 'app/client/ui2018/modals';
|
IModalControl, modal} from 'app/client/ui2018/modals';
|
||||||
|
|
||||||
export interface IUserManagerOptions {
|
export interface IUserManagerOptions {
|
||||||
permissionData: Promise<PermissionData>;
|
permissionData: Promise<PermissionData>;
|
||||||
|
@ -73,7 +73,10 @@ export function createNotFoundPage(appModel: AppModel, message?: string) {
|
|||||||
document.title = t("Page not found{{suffix}}", {suffix: getPageTitleSuffix(getGristConfig())});
|
document.title = t("Page not found{{suffix}}", {suffix: getPageTitleSuffix(getGristConfig())});
|
||||||
|
|
||||||
return pagePanelsError(appModel, t("Page not found{{suffix}}", {suffix: ''}), [
|
return pagePanelsError(appModel, t("Page not found{{suffix}}", {suffix: ''}), [
|
||||||
cssErrorText(message || t("The requested page could not be found.{{separator}}Please check the URL and try again.", {separator: dom('br')})), // TODO: i18next
|
cssErrorText(message ||
|
||||||
|
t("The requested page could not be found.{{separator}}Please check the URL and try again.", {
|
||||||
|
separator: dom('br')
|
||||||
|
})),
|
||||||
cssButtonWrap(bigPrimaryButtonLink(t("Go to main page"), testId('error-primary-btn'),
|
cssButtonWrap(bigPrimaryButtonLink(t("Go to main page"), testId('error-primary-btn'),
|
||||||
urlState().setLinkUrl({}))),
|
urlState().setLinkUrl({}))),
|
||||||
cssButtonWrap(bigBasicButtonLink(t("Contact support"), {href: 'https://getgrist.com/contact'})),
|
cssButtonWrap(bigBasicButtonLink(t("Contact support"), {href: 'https://getgrist.com/contact'})),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {theme, vars} from 'app/client/ui2018/cssVars';
|
import {theme, vars} from 'app/client/ui2018/cssVars';
|
||||||
import {dom, IDomArgs, DomElementArg, IInputOptions, Observable, styled, subscribe} from 'grainjs';
|
import {dom, DomElementArg, IDomArgs, IInputOptions, Observable, styled, subscribe} from 'grainjs';
|
||||||
|
|
||||||
export const cssInput = styled('input', `
|
export const cssInput = styled('input', `
|
||||||
font-size: ${vars.mediumFontSize};
|
font-size: ${vars.mediumFontSize};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ACResults, buildHighlightedDom, normalizeText, HighlightFunc } from 'app/client/lib/ACIndex';
|
import { ACResults, buildHighlightedDom, HighlightFunc, normalizeText } from 'app/client/lib/ACIndex';
|
||||||
import { Autocomplete } from 'app/client/lib/autocomplete';
|
import { Autocomplete } from 'app/client/lib/autocomplete';
|
||||||
import { ICellItem } from 'app/client/models/ColumnACIndexes';
|
import { ICellItem } from 'app/client/models/ColumnACIndexes';
|
||||||
import { reportError } from 'app/client/models/errors';
|
import { reportError } from 'app/client/models/errors';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createGroup } from 'app/client/components/commands';
|
import { createGroup } from 'app/client/components/commands';
|
||||||
import { ACItem, ACResults, normalizeText, HighlightFunc } from 'app/client/lib/ACIndex';
|
import { ACItem, ACResults, HighlightFunc, normalizeText } from 'app/client/lib/ACIndex';
|
||||||
import { IAutocompleteOptions } from 'app/client/lib/autocomplete';
|
import { IAutocompleteOptions } from 'app/client/lib/autocomplete';
|
||||||
import { IToken, TokenField, tokenFieldStyles } from 'app/client/lib/TokenField';
|
import { IToken, TokenField, tokenFieldStyles } from 'app/client/lib/TokenField';
|
||||||
import { reportError } from 'app/client/models/errors';
|
import { reportError } from 'app/client/models/errors';
|
||||||
|
@ -9,5 +9,5 @@ export default function getCurrentTime(): moment.Moment {
|
|||||||
if (typeof window === 'undefined' || !window) { return getDefault(); }
|
if (typeof window === 'undefined' || !window) { return getDefault(); }
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
const searchParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
return searchParams.has('currentTime') ? moment(searchParams.get('currentTime')!) : getDefault();
|
return searchParams.has('currentTime') ? moment(searchParams.get('currentTime')) : getDefault();
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import {makeId} from 'app/server/lib/idUtils';
|
|||||||
import log from 'app/server/lib/log';
|
import log from 'app/server/lib/log';
|
||||||
import {IPermitStore, Permit} from 'app/server/lib/Permit';
|
import {IPermitStore, Permit} from 'app/server/lib/Permit';
|
||||||
import {AccessTokenInfo} from 'app/server/lib/AccessTokens';
|
import {AccessTokenInfo} from 'app/server/lib/AccessTokens';
|
||||||
import {allowHost, isEnvironmentAllowedHost, getOriginUrl, optStringParam} from 'app/server/lib/requestUtils';
|
import {allowHost, getOriginUrl, isEnvironmentAllowedHost, optStringParam} from 'app/server/lib/requestUtils';
|
||||||
import * as cookie from 'cookie';
|
import * as cookie from 'cookie';
|
||||||
import {NextFunction, Request, RequestHandler, Response} from 'express';
|
import {NextFunction, Request, RequestHandler, Response} from 'express';
|
||||||
import {IncomingMessage} from 'http';
|
import {IncomingMessage} from 'http';
|
||||||
|
@ -955,8 +955,8 @@ export class DocWorkerApi {
|
|||||||
const options: DownloadOptions = {
|
const options: DownloadOptions = {
|
||||||
...params,
|
...params,
|
||||||
filename: name + (params.tableId === name ? '' : '-' + params.tableId),
|
filename: name + (params.tableId === name ? '' : '-' + params.tableId),
|
||||||
}
|
};
|
||||||
return options
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getActiveDoc(req: RequestWithLogin): Promise<ActiveDoc> {
|
private _getActiveDoc(req: RequestWithLogin): Promise<ActiveDoc> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {ApiError} from 'app/common/ApiError';
|
import {ApiError} from 'app/common/ApiError';
|
||||||
import {createFormatter} from 'app/common/ValueFormatter';
|
import {createFormatter} from 'app/common/ValueFormatter';
|
||||||
import {ActiveDoc} from 'app/server/lib/ActiveDoc';
|
import {ActiveDoc} from 'app/server/lib/ActiveDoc';
|
||||||
import {ExportData, exportSection, exportTable, Filter, DownloadOptions} from 'app/server/lib/Export';
|
import {DownloadOptions, ExportData, exportSection, exportTable, Filter} from 'app/server/lib/Export';
|
||||||
import log from 'app/server/lib/log';
|
import log from 'app/server/lib/log';
|
||||||
import * as bluebird from 'bluebird';
|
import * as bluebird from 'bluebird';
|
||||||
import contentDisposition from 'content-disposition';
|
import contentDisposition from 'content-disposition';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {ActiveDoc} from 'app/server/lib/ActiveDoc';
|
import {ActiveDoc} from 'app/server/lib/ActiveDoc';
|
||||||
import {createExcelFormatter} from 'app/server/lib/ExcelFormatter';
|
import {createExcelFormatter} from 'app/server/lib/ExcelFormatter';
|
||||||
import {ExportData, exportDoc, DownloadOptions, exportSection, exportTable, Filter} from 'app/server/lib/Export';
|
import {DownloadOptions, ExportData, exportDoc, exportSection, exportTable, Filter} from 'app/server/lib/Export';
|
||||||
import {Alignment, Border, Fill, Workbook} from 'exceljs';
|
import {Alignment, Border, Fill, Workbook} from 'exceljs';
|
||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
import log from 'app/server/lib/log';
|
import log from 'app/server/lib/log';
|
||||||
|
@ -923,7 +923,7 @@ export async function backupSqliteDatabase(src: string, dest: string,
|
|||||||
} finally {
|
} finally {
|
||||||
if (testProgress) { testProgress({action: 'close', phase: 'before'}); }
|
if (testProgress) { testProgress({action: 'close', phase: 'before'}); }
|
||||||
try {
|
try {
|
||||||
if (db) { await fromCallback(cb => db!.close(cb)); }
|
if (db) { await fromCallback(cb => db.close(cb)); }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_log.debug(null, `problem stopping copy of ${src} (${label}): ${err}`);
|
_log.debug(null, `problem stopping copy of ${src} (${label}): ${err}`);
|
||||||
}
|
}
|
||||||
|
@ -376,7 +376,7 @@ export class DocTriggers {
|
|||||||
|
|
||||||
private async _pushToRedisQueue(events: WebHookEvent[]) {
|
private async _pushToRedisQueue(events: WebHookEvent[]) {
|
||||||
const strings = events.map(e => JSON.stringify(e));
|
const strings = events.map(e => JSON.stringify(e));
|
||||||
await this._redisClient!.rpushAsync(this._redisQueueKey, ...strings);
|
await this._redisClient?.rpushAsync(this._redisQueueKey, ...strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getRedisQueue(redisClient: RedisClient) {
|
private async _getRedisQueue(redisClient: RedisClient) {
|
||||||
|
@ -108,7 +108,9 @@ export function allowHost(req: Request, allowedHost: string|URL) {
|
|||||||
// For requests to a native subdomains, only the base domain needs to match.
|
// For requests to a native subdomains, only the base domain needs to match.
|
||||||
const allowedDomain = parseSubdomain(allowedUrl.hostname);
|
const allowedDomain = parseSubdomain(allowedUrl.hostname);
|
||||||
const actualDomain = parseSubdomain(actualUrl.hostname);
|
const actualDomain = parseSubdomain(actualUrl.hostname);
|
||||||
return (!_.isEmpty(actualDomain) ? actualDomain.base === allowedDomain.base : allowedUrl.hostname === actualUrl.hostname);
|
return (!_.isEmpty(actualDomain) ?
|
||||||
|
actualDomain.base === allowedDomain.base :
|
||||||
|
allowedUrl.hostname === actualUrl.hostname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
"test:docker": "./test/test_under_docker.sh",
|
"test:docker": "./test/test_under_docker.sh",
|
||||||
"test:python": "sandbox_venv3/bin/python sandbox/grist/runtests.py ${GREP_TESTS:+discover -p \"test*${GREP_TESTS}*.py\"}",
|
"test:python": "sandbox_venv3/bin/python sandbox/grist/runtests.py ${GREP_TESTS:+discover -p \"test*${GREP_TESTS}*.py\"}",
|
||||||
"cli": "NODE_PATH=_build:_build/stubs:_build/ext node _build/app/server/companion.js",
|
"cli": "NODE_PATH=_build:_build/stubs:_build/ext node _build/app/server/companion.js",
|
||||||
"lint": "eslint .",
|
"lint": "eslint --cache --cache-strategy content .",
|
||||||
"lint:fix": "eslint --fix .",
|
"lint:fix": "eslint --cache --cache-strategy content --fix .",
|
||||||
"generate:translation": "NODE_PATH=_build:_build/stubs:_build/ext node buildtools/generate_translation_keys.js"
|
"generate:translation": "NODE_PATH=_build:_build/stubs:_build/ext node buildtools/generate_translation_keys.js"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
5
test/.eslintrc.js
Normal file
5
test/.eslintrc.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-shadow': 'off',
|
||||||
|
},
|
||||||
|
}
|
@ -2,14 +2,14 @@ import {makeT, t} from 'app/client/lib/localization';
|
|||||||
import {assert} from 'chai';
|
import {assert} from 'chai';
|
||||||
import i18next, {i18n} from 'i18next';
|
import i18next, {i18n} from 'i18next';
|
||||||
import {Disposable, dom, DomContents, observable} from "grainjs";
|
import {Disposable, dom, DomContents, observable} from "grainjs";
|
||||||
import {popGlobals, pushGlobals, G} from 'grainjs/dist/cjs/lib/browserGlobals';
|
import {G, popGlobals, pushGlobals} from 'grainjs/dist/cjs/lib/browserGlobals';
|
||||||
import {JSDOM} from 'jsdom';
|
import {JSDOM} from 'jsdom';
|
||||||
|
|
||||||
describe('localization', function() {
|
describe('localization', function() {
|
||||||
let instance: i18n;
|
let instance: i18n;
|
||||||
before(() => {
|
before(() => {
|
||||||
instance = i18next.createInstance();
|
instance = i18next.createInstance();
|
||||||
instance.init({
|
void instance.init({
|
||||||
lng: 'en',
|
lng: 'en',
|
||||||
resources: {
|
resources: {
|
||||||
en: {
|
en: {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-shadow */
|
||||||
import {ActionSummary} from 'app/common/ActionSummary';
|
import {ActionSummary} from 'app/common/ActionSummary';
|
||||||
import {BulkColValues, UserAction} from 'app/common/DocActions';
|
import {BulkColValues, UserAction} from 'app/common/DocActions';
|
||||||
import {arrayRepeat} from 'app/common/gutil';
|
import {arrayRepeat} from 'app/common/gutil';
|
||||||
@ -2103,7 +2104,10 @@ function testDocApi() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("GET /docs/{did}/download/xlsx returns 404 if tableId is invalid", async function() {
|
it("GET /docs/{did}/download/xlsx returns 404 if tableId is invalid", async function() {
|
||||||
const resp = await axios.get(`${serverUrl}/api/docs/${docIds.TestDoc}/download/xlsx?tableId=MissingTableId`, chimpy);
|
const resp = await axios.get(
|
||||||
|
`${serverUrl}/api/docs/${docIds.TestDoc}/download/xlsx?tableId=MissingTableId`,
|
||||||
|
chimpy
|
||||||
|
);
|
||||||
assert.equal(resp.status, 404);
|
assert.equal(resp.status, 404);
|
||||||
assert.deepEqual(resp.data, { error: 'Table MissingTableId not found.' });
|
assert.deepEqual(resp.data, { error: 'Table MissingTableId not found.' });
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
"include": [
|
"include": [
|
||||||
"app/**/*.js",
|
"app/**/*.js",
|
||||||
"app/**/*.ts",
|
"app/**/*.ts",
|
||||||
|
"stubs/**/*.ts",
|
||||||
|
"stubs/**/*.ts",
|
||||||
"test/**/*.js",
|
"test/**/*.js",
|
||||||
"test/**/*.ts",
|
"test/**/*.ts",
|
||||||
"plugins/**/*.js",
|
"plugins/**/*.js",
|
||||||
|
Loading…
Reference in New Issue
Block a user