(core) updates from grist-core

pull/833/head
Paul Fitzpatrick 4 months ago
commit fb276bade7

@ -9,8 +9,11 @@ import {icon} from 'app/client/ui2018/icons';
import {cssModalTooltip, modalTooltip} from 'app/client/ui2018/modals';
import {dom, DomContents, keyframes, observable, styled, svg} from 'grainjs';
import {IPopupOptions} from 'popweasel';
import {makeT} from 'app/client/lib/localization';
import merge = require('lodash/merge');
const t = makeT('modals');
/**
* This is a file for all custom and pre-configured popups, modals, toasts and tooltips, used
* in more then one component.
@ -35,19 +38,21 @@ export function buildConfirmDelete(
Escape: () => ctl.close(),
Enter: () => { onSave(remember.get()); ctl.close(); },
}),
dom('div', `Are you sure you want to delete ${single ? 'this' : 'these'} record${single ? '' : 's'}?`,
dom('div', single ?
t(`Are you sure you want to delete this record?`)
: t(`Are you sure you want to delete these records?`),
dom.style('margin-bottom', '10px'),
),
dom('div',
labeledSquareCheckbox(remember, "Don't ask again.", testId('confirm-remember')),
labeledSquareCheckbox(remember, t("Don't ask again."), testId('confirm-remember')),
dom.style('margin-bottom', '10px'),
),
cssButtons(
primaryButton('Delete', testId('confirm-save'), dom.on('click', () => {
primaryButton(t('Delete'), testId('confirm-save'), dom.on('click', () => {
onSave(remember.get());
ctl.close();
})),
basicButton('Cancel', testId('confirm-cancel'), dom.on('click', () => ctl.close()))
basicButton(t('Cancel'), testId('confirm-cancel'), dom.on('click', () => ctl.close()))
)
), {}
);
@ -81,9 +86,9 @@ export function showDeprecatedWarning(
dom.style('justify-content', 'space-between'),
dom.style('align-items', 'center'),
dom('div',
labeledSquareCheckbox(remember, "Don't show again.", testId('confirm-remember')),
labeledSquareCheckbox(remember, t("Don't show again."), testId('confirm-remember')),
),
basicButton('Dismiss', testId('confirm-save'),
basicButton(t('Dismiss'), testId('confirm-save'),
dom.on('click', () => { ctl.close(); onClose(remember.get()); })
)
),
@ -105,7 +110,7 @@ export function showDeprecatedWarning(
export function reportUndo(
doc: GristDoc,
messageLabel: string,
buttonLabel = 'Undo to restore'
buttonLabel = t('Undo to restore')
) {
// First create a notification with a button to undo the delete.
let notification = reportSuccess(messageLabel, {
@ -179,12 +184,12 @@ export function showBehavioralPrompt(
dom.style('align-items', 'center'),
dom('div',
cssSkipTipsCheckbox(dontShowTips,
cssSkipTipsCheckboxLabel("Don't show tips"),
cssSkipTipsCheckboxLabel(t("Don't show tips")),
testId('behavioral-prompt-dont-show-tips')
),
dom.style('visibility', hideDontShowTips ? 'hidden' : ''),
),
cssDismissPromptButton('Got it', testId('behavioral-prompt-dismiss'),
cssDismissPromptButton(t('Got it'), testId('behavioral-prompt-dismiss'),
dom.on('click', () => { onClose(dontShowTips.get()); ctl.close(); })
),
),

@ -526,11 +526,19 @@ export class Client {
}
}
private async _onMessage(message: string): Promise<void> {
try {
await this._onMessageImpl(message);
} catch (err) {
this._log.warn(null, 'onMessage error received for message "%s": %s', shortDesc(message), err.stack);
}
}
/**
* Processes a request from a client. All requests from a client get a response, at least to
* indicate success or failure.
*/
private async _onMessage(message: string): Promise<void> {
private async _onMessageImpl(message: string): Promise<void> {
const request = JSON.parse(message);
if (request.beat) {
// this is a heart beat, to keep the websocket alive. No need to reply.

@ -433,7 +433,19 @@
"Created by": "Created by",
"Detect duplicates in...": "Detect duplicates in...",
"Last updated at": "Last updated at",
"Last updated by": "Last updated by"
"Last updated by": "Last updated by",
"Any": "Any",
"Numeric": "Numeric",
"Text": "Text",
"Integer": "Integer",
"Toggle": "Toggle",
"Date": "Date",
"DateTime": "DateTime",
"Choice": "Choice",
"Choice List": "Choice List",
"Reference": "Reference",
"Reference List": "Reference List",
"Attachment": "Attachment"
},
"GristDoc": {
"Added new linked section to view {{viewName}}": "Added new linked section to view {{viewName}}",
@ -622,7 +634,23 @@
"Widget": "Widget",
"You do not have edit access to this document": "You do not have edit access to this document",
"Add referenced columns": "Add referenced columns",
"Reset form": "Reset form"
"Reset form": "Reset form",
"Configuration": "Configuration",
"Default field value": "Default field value",
"Display button": "Display button",
"Enter text": "Enter text",
"Field rules": "Field rules",
"Field title": "Field title",
"Hidden field": "Hidden field",
"Layout": "Layout",
"Redirect automatically after submission": "Redirect automatically after submission",
"Redirection": "Redirection",
"Required field": "Required field",
"Submission": "Submission",
"Submit another response": "Submit another response",
"Submit button label": "Submit button label",
"Success text": "Success text",
"Table column name": "Table column name"
},
"RowContextMenu": {
"Copy anchor link": "Copy anchor link",
@ -761,7 +789,8 @@
"Show raw data": "Show raw data",
"Widget options": "Widget options",
"Add to page": "Add to page",
"Collapse widget": "Collapse widget"
"Collapse widget": "Collapse widget",
"Create a form": "Create a form"
},
"ViewSectionMenu": {
"(customized)": "(customized)",
@ -863,7 +892,16 @@
"modals": {
"Cancel": "Cancel",
"Ok": "OK",
"Save": "Save"
"Save": "Save",
"Are you sure you want to delete these records?": "Are you sure you want to delete these records?",
"Are you sure you want to delete this record?": "Are you sure you want to delete this record?",
"Delete": "Delete",
"Dismiss": "Dismiss",
"Don't ask again.": "Don't ask again.",
"Don't show again.": "Don't show again.",
"Don't show tips": "Don't show tips",
"Undo to restore": "Undo to restore",
"Got it": "Got it"
},
"pages": {
"Duplicate Page": "Duplicate Page",
@ -1266,5 +1304,28 @@
"Publish your form?": "Publish your form?",
"Unpublish": "Unpublish",
"Unpublish your form?": "Unpublish your form?"
},
"Editor": {
"Delete": "Delete"
},
"Menu": {
"Building blocks": "Building blocks",
"Columns": "Columns",
"Copy": "Copy",
"Cut": "Cut",
"Insert question above": "Insert question above",
"Insert question below": "Insert question below",
"Paragraph": "Paragraph",
"Paste": "Paste",
"Separator": "Separator",
"Unmapped fields": "Unmapped fields"
},
"UnmappedFieldsConfig": {
"Clear": "Clear",
"Map fields": "Map fields",
"Mapped": "Mapped",
"Select All": "Select All",
"Unmap fields": "Unmap fields",
"Unmapped": "Unmapped"
}
}

@ -188,6 +188,24 @@ describe('Comm', function() {
]);
});
it('should only log warning for malformed JSON data', async function () {
const logMessages = await testUtils.captureLog('warn', async () => {
ws.send('foobar');
}, {waitForFirstLog: true});
testUtils.assertMatchArray(logMessages, [
/^warn: Client.* Unexpected token.*/
]);
});
it('should log warning when null value is passed', async function () {
const logMessages = await testUtils.captureLog('warn', async () => {
ws.send('null');
}, {waitForFirstLog: true});
testUtils.assertMatchArray(logMessages, [
/^warn: Client.*Cannot read properties of null*/
]);
});
it("should support app-level events correctly", async function() {
comm!.broadcastMessage('fooType' as any, 'hello');
comm!.broadcastMessage('barType' as any, 'world');

@ -126,25 +126,32 @@ export function setTmpLogLevel(level: string, optCaptureFunc?: (level: string, m
*/
export async function captureLog(
minLevel: string, callback: (messages: string[]) => void|Promise<void>,
options: {timestamp: boolean} = {timestamp: false}
options: {timestamp?: boolean, waitForFirstLog?: boolean} = {timestamp: false, waitForFirstLog: false}
): Promise<string[]> {
const messages: string[] = [];
const prevLogLevel = log.transports.file.level;
const name = _.uniqueId('CaptureLog');
function capture(level: string, msg: string, meta: any) {
if ((log as any).levels[level] <= (log as any).levels[minLevel]) { // winston types are off?
const timePrefix = options.timestamp ? new Date().toISOString() + ' ' : '';
messages.push(`${timePrefix}${level}: ${msg}${meta ? ' ' + serialize(meta) : ''}`);
const captureFirstLogPromise = new Promise((resolve) => {
function capture(level: string, msg: string, meta: any) {
if ((log as any).levels[level] <= (log as any).levels[minLevel]) { // winston types are off?
const timePrefix = options.timestamp ? new Date().toISOString() + ' ' : '';
messages.push(`${timePrefix}${level}: ${msg}${meta ? ' ' + serialize(meta) : ''}`);
resolve(null);
}
}
}
if (!process.env.VERBOSE) {
log.transports.file.level = -1 as any; // Suppress all log output.
}
log.add(CaptureTransport as any, { captureFunc: capture, name, level: minLevel}); // types are off.
if (!process.env.VERBOSE) {
log.transports.file.level = -1 as any; // Suppress all log output.
}
log.add(CaptureTransport as any, { captureFunc: capture, name, level: minLevel}); // types are off.
});
try {
await callback(messages);
if (options.waitForFirstLog) {
await captureFirstLogPromise;
}
} finally {
log.remove(name);
log.transports.file.level = prevLogLevel;

Loading…
Cancel
Save