(core) passing language as a query parameter to custom widgets

Summary: to allow custom widget having optional translations, lagunage seeted in user profile is passed as query parameter to custom widget

Test Plan: test added to check if query parameter is existing in url when settings is changed in profile

Reviewers: georgegevoian

Reviewed By: georgegevoian

Subscribers: jarek, paulfitz

Differential Revision: https://phab.getgrist.com/D4045
This commit is contained in:
Jakub Serafin 2023-10-02 15:57:20 +02:00
parent fbae81648c
commit 498ad07d38
4 changed files with 521 additions and 426 deletions

View File

@ -25,6 +25,7 @@ import {UserError} from 'app/client/models/errors';
import {SortedRowSet} from 'app/client/models/rowset';
import {closeRegisteredMenu} from 'app/client/ui2018/menus';
import {AccessLevel} from 'app/common/CustomWidget';
import {defaultLocale} from 'app/common/gutil';
import {PluginInstance} from 'app/common/PluginInstance';
import {getGristConfig} from 'app/common/urlUtils';
import {Events as BackboneEvents} from 'backbone';
@ -213,9 +214,17 @@ export class CustomView extends Disposable {
showAfterReady?: boolean,
}) {
const {baseUrl, access, showAfterReady} = options;
const documentSettings = this.gristDoc.docData.docSettings();
return grains.create(WidgetFrame, {
url: baseUrl || this.getEmptyWidgetPage(),
access,
preferences:
{
culture: documentSettings.locale?? defaultLocale,
language: this.gristDoc.appModel.currentUser?.locale ?? defaultLocale,
timeZone: this.gristDoc.docInfo.timezone() ?? "UTC",
currency: documentSettings.currency?? "USD",
},
readonly: this.gristDoc.isReadonly.get(),
showAfterReady,
onSettingsInitialized: async () => {

View File

@ -73,6 +73,10 @@ export interface WidgetFrameOptions {
* Optional handler to modify the iframe.
*/
onElem?: (iframe: HTMLIFrameElement) => void;
/**
* Optional language to use for the widget.
*/
preferences: {language?: string, timeZone?: any, currency?: string, culture?: string};
}
/**
@ -175,6 +179,9 @@ export class WidgetFrame extends DisposableWithEvents {
const urlObj = new URL(url);
urlObj.searchParams.append('access', this._options.access);
urlObj.searchParams.append('readonly', String(this._options.readonly));
// Append user and document preferences to query string.
const settingsParams = new URLSearchParams(this._options.preferences);
settingsParams.forEach((value, key) => urlObj.searchParams.append(key, value));
return urlObj.href;
};
const fullUrl = urlWithAccess(this._options.url);

File diff suppressed because it is too large Load Diff

View File

@ -859,6 +859,19 @@ export async function importUrlDialog(url: string): Promise<void> {
await driver.switchTo().defaultContent();
}
/**
* Executed passed function in the context of given iframe, and then switching back to original context
*
*/
export async function doInIframe<T>(iframe: WebElement, func: () => Promise<T>) {
try {
await driver.switchTo().frame(iframe);
return await func();
} finally {
await driver.switchTo().defaultContent();
}
}
/**
* 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