Skip to content

Commit 1bd23a3

Browse files
committed
Merge remote-tracking branch 'refs/remotes/origin/dev' into stable
2 parents 1be3b75 + 017b55b commit 1bd23a3

File tree

6 files changed

+180
-90
lines changed

6 files changed

+180
-90
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export const CREATE_LOCALE = /* GraphQL */ `
2+
mutation CreateI18NLocale($data: I18NLocaleInput!) {
3+
i18n {
4+
createI18NLocale(data: $data) {
5+
data {
6+
code
7+
}
8+
error {
9+
message
10+
code
11+
}
12+
}
13+
}
14+
}
15+
`;

packages/api-form-builder/__tests__/settings.test.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import useGqlHandler from "./useGqlHandler";
2+
import { GET_SETTINGS } from "~tests/graphql/formBuilderSettings";
23

34
describe("Settings Test", () => {
4-
const { getSettings, updateSettings, install, isInstalled } = useGqlHandler();
5+
const { getSettings, updateSettings, install, createI18NLocale, isInstalled } = useGqlHandler();
56

67
test(`Should not be able to get & update settings before "install"`, async () => {
78
// Should not have any settings without install
@@ -154,4 +155,41 @@ describe("Settings Test", () => {
154155
}
155156
});
156157
});
158+
159+
test(`Should be able to get & update settings after in a new locale`, async () => {
160+
// Let's install the `Form builder`
161+
await install({ domain: "http://localhost:3001" });
162+
163+
await createI18NLocale({ data: { code: "de-DE" } });
164+
165+
const { invoke } = useGqlHandler();
166+
167+
// Had to do it via `invoke` directly because this way it's possible to
168+
// set the locale header. Wasn't easily possible via the `getSettings` helper.
169+
const [newLocaleFbSettings] = await invoke({
170+
body: { query: GET_SETTINGS },
171+
headers: {
172+
"x-i18n-locale": "default:de-DE;content:de-DE;"
173+
}
174+
});
175+
176+
// Settings should exist in the newly created locale.
177+
expect(newLocaleFbSettings).toEqual({
178+
data: {
179+
formBuilder: {
180+
getSettings: {
181+
data: {
182+
domain: null,
183+
reCaptcha: {
184+
enabled: null,
185+
secretKey: null,
186+
siteKey: null
187+
}
188+
},
189+
error: null
190+
}
191+
}
192+
}
193+
});
194+
});
157195
});

packages/api-form-builder/__tests__/useGqlHandler.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ import i18nContext from "@webiny/api-i18n/graphql/context";
88
import { mockLocalesPlugins } from "@webiny/api-i18n/graphql/testing";
99
import { SecurityIdentity, SecurityPermission } from "@webiny/api-security/types";
1010
import { createFormBuilder } from "~/index";
11+
import { createI18NGraphQL } from "@webiny/api-i18n/graphql";
12+
1113
// Graphql
1214
import { INSTALL as INSTALL_FILE_MANAGER } from "./graphql/fileManagerSettings";
15+
import { CREATE_LOCALE } from "./graphql/i18n";
16+
1317
import {
1418
GET_SETTINGS,
1519
INSTALL,
@@ -41,11 +45,7 @@ import { PluginCollection } from "@webiny/plugins/types";
4145
import { getStorageOps } from "@webiny/project-utils/testing/environment";
4246
import { FileManagerStorageOperations } from "@webiny/api-file-manager/types";
4347
import { HeadlessCmsStorageOperations } from "@webiny/api-headless-cms/types";
44-
import {
45-
CmsParametersPlugin,
46-
createHeadlessCmsContext,
47-
createHeadlessCmsGraphQL
48-
} from "@webiny/api-headless-cms";
48+
import { createHeadlessCmsContext, createHeadlessCmsGraphQL } from "@webiny/api-headless-cms";
4949
import { FormBuilderStorageOperations } from "~/types";
5050
import { APIGatewayEvent, LambdaContext } from "@webiny/handler-aws/types";
5151
import { createPageBuilderContext } from "@webiny/api-page-builder";
@@ -83,14 +83,9 @@ export default (params: UseGqlHandlerParams = {}) => {
8383
graphqlHandlerPlugins(),
8484
...createTenancyAndSecurity({ permissions, identity }),
8585
i18nContext(),
86+
createI18NGraphQL(),
8687
i18nStorage.storageOperations,
8788
mockLocalesPlugins(),
88-
new CmsParametersPlugin(async () => {
89-
return {
90-
locale: "en-US",
91-
type: "manage"
92-
};
93-
}),
9489
createHeadlessCmsContext({ storageOperations: cmsStorage.storageOperations }),
9590
createHeadlessCmsGraphQL(),
9691
createPageBuilderContext({
@@ -228,6 +223,11 @@ export default (params: UseGqlHandlerParams = {}) => {
228223
},
229224
async exportFormSubmissions(variables: Record<string, any>) {
230225
return invoke({ body: { query: EXPORT_FORM_SUBMISSIONS, variables } });
226+
},
227+
228+
// Locales.
229+
async createI18NLocale(variables: Record<string, any>) {
230+
return invoke({ body: { query: CREATE_LOCALE, variables } });
231231
}
232232
};
233233
};

packages/api-form-builder/src/plugins/crud/index.ts

Lines changed: 90 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -15,94 +15,107 @@ export interface CreateFormBuilderCrudParams {
1515
export default (params: CreateFormBuilderCrudParams) => {
1616
const { storageOperations } = params;
1717

18-
return new ContextPlugin<FormBuilderContext>(async context => {
19-
const getLocale = () => {
20-
const locale = context.i18n.getContentLocale();
21-
if (!locale) {
22-
throw new WebinyError(
23-
"Missing locale on context.i18n locale in API Form Builder.",
24-
"LOCALE_ERROR"
25-
);
18+
return [
19+
new ContextPlugin<FormBuilderContext>(async context => {
20+
const getLocale = () => {
21+
const locale = context.i18n.getContentLocale();
22+
if (!locale) {
23+
throw new WebinyError(
24+
"Missing locale on context.i18n locale in API Form Builder.",
25+
"LOCALE_ERROR"
26+
);
27+
}
28+
return locale;
29+
};
30+
31+
const getIdentity = () => {
32+
return context.security.getIdentity();
33+
};
34+
35+
const getTenant = () => {
36+
return context.tenancy.getCurrentTenant();
37+
};
38+
39+
if (storageOperations.beforeInit) {
40+
try {
41+
await storageOperations.beforeInit(context);
42+
} catch (ex) {
43+
throw new WebinyError(
44+
ex.message ||
45+
"Could not run before init in Form Builder storage operations.",
46+
ex.code || "STORAGE_OPERATIONS_BEFORE_INIT_ERROR",
47+
{
48+
...ex
49+
}
50+
);
51+
}
2652
}
27-
return locale;
28-
};
2953

30-
const getIdentity = () => {
31-
return context.security.getIdentity();
32-
};
54+
const basePermissionsArgs = {
55+
getIdentity,
56+
fullAccessPermissionName: "fb.*"
57+
};
58+
59+
const formsPermissions = new FormsPermissions({
60+
...basePermissionsArgs,
61+
getPermissions: () => context.security.getPermissions("fb.form")
62+
});
3363

34-
const getTenant = () => {
35-
return context.tenancy.getCurrentTenant();
36-
};
64+
const settingsPermissions = new SettingsPermissions({
65+
...basePermissionsArgs,
66+
getPermissions: () => context.security.getPermissions("fb.settings")
67+
});
3768

38-
if (storageOperations.beforeInit) {
69+
context.formBuilder = {
70+
storageOperations,
71+
...createSystemCrud({
72+
getIdentity,
73+
getTenant,
74+
getLocale,
75+
context
76+
}),
77+
...createSettingsCrud({
78+
getTenant,
79+
getLocale,
80+
settingsPermissions,
81+
context
82+
}),
83+
...createFormsCrud({
84+
getTenant,
85+
getLocale,
86+
formsPermissions,
87+
context
88+
}),
89+
...createSubmissionsCrud({
90+
context,
91+
formsPermissions
92+
})
93+
};
94+
95+
if (!storageOperations.init) {
96+
return;
97+
}
3998
try {
40-
await storageOperations.beforeInit(context);
99+
await storageOperations.init(context);
41100
} catch (ex) {
42101
throw new WebinyError(
43-
ex.message || "Could not run before init in Form Builder storage operations.",
44-
ex.code || "STORAGE_OPERATIONS_BEFORE_INIT_ERROR",
102+
ex.message || "Could not run init in Form Builder storage operations.",
103+
ex.code || "STORAGE_OPERATIONS_INIT_ERROR",
45104
{
46105
...ex
47106
}
48107
);
49108
}
50-
}
51-
52-
const basePermissionsArgs = {
53-
getIdentity,
54-
fullAccessPermissionName: "fb.*"
55-
};
56-
57-
const formsPermissions = new FormsPermissions({
58-
...basePermissionsArgs,
59-
getPermissions: () => context.security.getPermissions("fb.form")
60-
});
109+
}),
61110

62-
const settingsPermissions = new SettingsPermissions({
63-
...basePermissionsArgs,
64-
getPermissions: () => context.security.getPermissions("fb.settings")
65-
});
66-
67-
context.formBuilder = {
68-
storageOperations,
69-
...createSystemCrud({
70-
getIdentity,
71-
getTenant,
72-
getLocale,
73-
context
74-
}),
75-
...createSettingsCrud({
76-
getTenant,
77-
getLocale,
78-
settingsPermissions,
79-
context
80-
}),
81-
...createFormsCrud({
82-
getTenant,
83-
getLocale,
84-
formsPermissions,
85-
context
86-
}),
87-
...createSubmissionsCrud({
88-
context,
89-
formsPermissions
90-
})
91-
};
92-
93-
if (!storageOperations.init) {
94-
return;
95-
}
96-
try {
97-
await storageOperations.init(context);
98-
} catch (ex) {
99-
throw new WebinyError(
100-
ex.message || "Could not run init in Form Builder storage operations.",
101-
ex.code || "STORAGE_OPERATIONS_INIT_ERROR",
102-
{
103-
...ex
104-
}
105-
);
106-
}
107-
});
111+
// Once a new locale is created, we need to create a new settings entry for it.
112+
new ContextPlugin<FormBuilderContext>(async context => {
113+
context.i18n.locales.onLocaleAfterCreate.subscribe(async params => {
114+
const { locale } = params;
115+
await context.i18n.withLocale(locale, async () => {
116+
return context.formBuilder.createSettings({});
117+
});
118+
});
119+
})
120+
];
108121
};

packages/api-i18n/src/graphql/context.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,25 @@ const createBaseContextPlugin = () => {
239239
return results;
240240
};
241241

242+
const withLocale: I18NContextObject["withLocale"] = async (locale, cb) => {
243+
const initialLocale = getDefaultLocale();
244+
if (!initialLocale) {
245+
return;
246+
}
247+
248+
setContentLocale(locale);
249+
setCurrentLocale("default", locale);
250+
251+
try {
252+
// We have to await the callback, because, in case it's an async function,
253+
// the `finally` block would get executed before the callback finishes.
254+
return await cb();
255+
} finally {
256+
setContentLocale(initialLocale);
257+
setCurrentLocale("default", initialLocale);
258+
}
259+
};
260+
242261
context.i18n = {
243262
...context.i18n,
244263
getDefaultLocale,
@@ -252,7 +271,8 @@ const createBaseContextPlugin = () => {
252271
reloadLocales,
253272
hasI18NContentPermission: () => hasI18NContentPermission(context),
254273
checkI18NContentPermission,
255-
withEachLocale
274+
withEachLocale,
275+
withLocale
256276
};
257277
});
258278
};

packages/api-i18n/src/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ export interface I18NContextObject {
4444
locales: I18NLocale[],
4545
cb: (locale: I18NLocale) => Promise<TReturn>
4646
) => Promise<TReturn[] | undefined>;
47+
withLocale: <TReturn>(
48+
locale: I18NLocale,
49+
cb: () => Promise<TReturn>
50+
) => Promise<TReturn | undefined>;
4751
}
4852

4953
export interface SystemInstallParams {

0 commit comments

Comments
 (0)