mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) updates from grist-core
This commit is contained in:
@@ -113,7 +113,9 @@ export class AccountPage extends Disposable {
|
||||
),
|
||||
css.subHeader(t("Two-factor authentication")),
|
||||
css.description(
|
||||
t("Two-factor authentication is an extra layer of security for your Grist account designed to ensure that you're the only person who can access your account, even if someone knows your password.")
|
||||
t("Two-factor authentication is an extra layer of security for your Grist account " +
|
||||
"designed to ensure that you're the only person who can access your account, " +
|
||||
"even if someone knows your password.")
|
||||
),
|
||||
dom.create(MFAConfig, user),
|
||||
),
|
||||
|
||||
@@ -78,7 +78,8 @@ export class ApiKey extends Disposable {
|
||||
dom.maybe((use) => !(use(this._apiKey) || this._anonymous), () => [
|
||||
basicButton(t("Create"), dom.on('click', () => this._onCreate()), testId('create'),
|
||||
dom.boolAttr('disabled', this._loading)),
|
||||
description(t("By generating an API key, you will be able to make API calls for your own account."), testId('description')),
|
||||
description(t("By generating an API key, you will be able to " +
|
||||
"make API calls for your own account."), testId('description')),
|
||||
]),
|
||||
);
|
||||
}
|
||||
@@ -114,7 +115,8 @@ export class ApiKey extends Disposable {
|
||||
confirmModal(
|
||||
t("Remove API Key"), t("Remove"),
|
||||
() => this._onDelete(),
|
||||
t("You're about to delete an API key. This will cause all future requests using this API key to be rejected. Do you still want to delete?")
|
||||
t("You're about to delete an API key. This will cause all future requests " +
|
||||
"using this API key to be rejected. Do you still want to delete?")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,9 @@ class ColumnPicker extends Disposable {
|
||||
properValue,
|
||||
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),
|
||||
@@ -117,7 +119,11 @@ class ColumnListPicker extends Disposable {
|
||||
col.label.peek(),
|
||||
)),
|
||||
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)
|
||||
) : null
|
||||
];
|
||||
@@ -371,8 +377,12 @@ export class CustomSectionConfig extends Disposable {
|
||||
}
|
||||
switch(level) {
|
||||
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.full: return cssConfirmLine(t("Widget needs {{fullAccess}} to this document.", {fullAccess: dom("b", "full access")})); // TODO i18next
|
||||
case AccessLevel.read_table:
|
||||
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`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ export async function startDocTour(docData: DocData, docComm: DocComm, onFinishC
|
||||
|
||||
const invalidDocTour: IOnBoardingMsg[] = [{
|
||||
title: t("No valid document tour"),
|
||||
body: t("Cannot construct a document tour from the data in this document. Ensure there is a table named GristDocTour with columns Title, Body, Placement, and Location."),
|
||||
body: t("Cannot construct a document tour from the data in this document. " +
|
||||
"Ensure there is a table named GristDocTour with columns Title, Body, Placement, and Location."),
|
||||
selector: 'document',
|
||||
showHasModal: true,
|
||||
}];
|
||||
|
||||
@@ -58,7 +58,7 @@ export async function showDocSettingsModal(docInfo: DocInfoRec, docPageModel: Do
|
||||
canChangeEngine ? [
|
||||
// Small easter egg: you can click on the skull-and-crossbones to
|
||||
// force a reload of the document.
|
||||
cssDataRow(t("Engine (experimental {{span}} change at own risk):", {span:
|
||||
cssDataRow(t("Engine (experimental {{span}} change at own risk):", {span:
|
||||
dom('span', '☠',
|
||||
dom.style('cursor', 'pointer'),
|
||||
dom.on('click', async () => {
|
||||
|
||||
@@ -83,10 +83,9 @@ class DuplicateTableModal extends Disposable {
|
||||
),
|
||||
cssWarning(
|
||||
cssWarningIcon('Warning'),
|
||||
|
||||
dom('div',
|
||||
t("Instead of duplicating tables, it's usually better to segment data using linked views. {{link}}", {link: cssLink({href: commonUrls.helpLinkingWidgets, target: '_blank'}, 'Read More.')})
|
||||
), //TODO: i18next
|
||||
dom('div', t("Instead of duplicating tables, it's usually better to segment data using linked views. {{link}}",
|
||||
{link: cssLink({href: commonUrls.helpLinkingWidgets, target: '_blank'}, 'Read More.')}
|
||||
)),
|
||||
),
|
||||
cssField(
|
||||
cssCheckbox(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {makeT} from 'app/client/lib/localization'
|
||||
import {makeT} from 'app/client/lib/localization';
|
||||
|
||||
const t = makeT('ExampleInfo');
|
||||
|
||||
@@ -36,7 +36,8 @@ export const buildExamples = (): IExampleInfo[] => [{
|
||||
tutorialUrl: 'https://support.getgrist.com/investment-research/',
|
||||
welcomeCard: {
|
||||
title: t("Welcome to the Investment Research template"),
|
||||
text: t("Check out our related tutorial to learn how to create summary tables and charts, and to link charts dynamically."),
|
||||
text: t("Check out our related tutorial to learn how to create " +
|
||||
"summary tables and charts, and to link charts dynamically."),
|
||||
tutorialName: t("Tutorial: Analyze & Visualize"),
|
||||
},
|
||||
}, {
|
||||
|
||||
@@ -41,7 +41,8 @@ export async function replaceTrunkWithFork(user: FullUser|null, doc: Document, a
|
||||
if (cmp.summary === 'left' || cmp.summary === 'both') {
|
||||
titleText = t("Original Has Modifications");
|
||||
buttonText = t("Overwrite");
|
||||
warningText = `${warningText} ${t("Be careful, the original has changes not in this document. Those changes will be overwritten.")}`;
|
||||
warningText = `${warningText} ${t("Be careful, the original has changes " +
|
||||
"not in this document. Those changes will be overwritten.")}`;
|
||||
} else if (cmp.summary === 'unrelated') {
|
||||
titleText = t("Original Looks Unrelated");
|
||||
buttonText = t("Overwrite");
|
||||
|
||||
@@ -268,8 +268,8 @@ export class PageWidgetSelect extends Disposable {
|
||||
}) :
|
||||
null;
|
||||
|
||||
private _isNewTableDisabled = Computed.create(this, this._value.type, (use, t) => !isValidSelection(
|
||||
'New Table', t, this._options.isNewPage));
|
||||
private _isNewTableDisabled = Computed.create(this, this._value.type, (use, type) => !isValidSelection(
|
||||
'New Table', type, this._options.isNewPage));
|
||||
|
||||
constructor(
|
||||
private _value: IWidgetValueObs,
|
||||
@@ -399,8 +399,8 @@ export class PageWidgetSelect extends Disposable {
|
||||
this._value.summarize.set(true);
|
||||
}
|
||||
|
||||
private _selectType(t: IWidgetType) {
|
||||
this._value.type.set(t);
|
||||
private _selectType(type: IWidgetType) {
|
||||
this._value.type.set(type);
|
||||
}
|
||||
|
||||
private _selectTable(tid: TableId) {
|
||||
|
||||
@@ -100,11 +100,11 @@ function removeView(activeDoc: GristDoc, viewId: number, pageName: string) {
|
||||
const removePage = () => [['RemoveRecord', '_grist_Views', viewId]];
|
||||
const removeAll = () => [
|
||||
...removePage(),
|
||||
...notVisibleTables.map(t => ['RemoveTable', t.tableId.peek()])
|
||||
...notVisibleTables.map(tb => ['RemoveTable', tb.tableId.peek()])
|
||||
];
|
||||
|
||||
if (notVisibleTables.length) {
|
||||
const tableNames = notVisibleTables.map(t => t.tableNameDef.peek());
|
||||
const tableNames = notVisibleTables.map(tb => tb.tableNameDef.peek());
|
||||
buildPrompt(tableNames, async (option) => {
|
||||
// Errors are handled in the dialog.
|
||||
if (option === 'data') {
|
||||
@@ -174,7 +174,7 @@ function buildOption(value: Observable<RemoveOption>, id: RemoveOption, content:
|
||||
|
||||
function buildWarning(tables: string[]) {
|
||||
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 {loadingSpinner} from 'app/client/ui2018/loaders';
|
||||
import {menu, menuItem, menuText} from 'app/client/ui2018/menus';
|
||||
import {confirmModal, cssModalBody, cssModalButtons, cssModalTitle, IModalControl,
|
||||
modal, cssAnimatedModal} from 'app/client/ui2018/modals';
|
||||
import {confirmModal, cssAnimatedModal, cssModalBody, cssModalButtons, cssModalTitle,
|
||||
IModalControl, modal} from 'app/client/ui2018/modals';
|
||||
|
||||
export interface IUserManagerOptions {
|
||||
permissionData: Promise<PermissionData>;
|
||||
|
||||
@@ -35,7 +35,8 @@ export function createForbiddenPage(appModel: AppModel, message?: string) {
|
||||
return pagePanelsError(appModel, t("Access denied{{suffix}}", {suffix: ''}), [
|
||||
dom.domComputed(appModel.currentValidUser, user => user ? [
|
||||
cssErrorText(message || t("You do not have access to this organization's documents.")),
|
||||
cssErrorText(t("You are signed in as {{email}}. You can sign in with a different account, or ask an administrator for access.", {email: dom('b', user.email)})), // TODO: i18next
|
||||
cssErrorText(t("You are signed in as {{email}}. You can sign in with a different " +
|
||||
"account, or ask an administrator for access.", {email: dom('b', user.email)})),
|
||||
] : [
|
||||
// This page is not normally shown because a logged out user with no access will get
|
||||
// redirected to log in. But it may be seen if a user logs out and returns to a cached
|
||||
@@ -58,7 +59,7 @@ export function createForbiddenPage(appModel: AppModel, message?: string) {
|
||||
export function createSignedOutPage(appModel: AppModel) {
|
||||
document.title = t("Signed out{{suffix}}", {suffix: getPageTitleSuffix(getGristConfig())});
|
||||
|
||||
return pagePanelsError(appModel, t("Signed out{{suffix}}", {suffix: ''}), [
|
||||
return pagePanelsError(appModel, t("Signed out{{suffix}}", {suffix: ''}), [
|
||||
cssErrorText(t("You are now signed out.")),
|
||||
cssButtonWrap(bigPrimaryButtonLink(
|
||||
t("Sign in again"), {href: getLoginUrl()}, testId('error-signin')
|
||||
@@ -73,7 +74,10 @@ export function createNotFoundPage(appModel: AppModel, message?: string) {
|
||||
document.title = t("Page not found{{suffix}}", {suffix: getPageTitleSuffix(getGristConfig())});
|
||||
|
||||
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'),
|
||||
urlState().setLinkUrl({}))),
|
||||
cssButtonWrap(bigBasicButtonLink(t("Contact support"), {href: 'https://getgrist.com/contact'})),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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', `
|
||||
font-size: ${vars.mediumFontSize};
|
||||
|
||||
Reference in New Issue
Block a user