@raketa-cloud/admin 1.9.4 → 1.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1862,9 +1862,9 @@ select {
1862
1862
  height: 3rem;
1863
1863
  }
1864
1864
 
1865
- .size-14 {
1866
- width: 3.5rem;
1867
- height: 3.5rem;
1865
+ .size-16 {
1866
+ width: 4rem;
1867
+ height: 4rem;
1868
1868
  }
1869
1869
 
1870
1870
  .size-3 {
@@ -1994,10 +1994,6 @@ select {
1994
1994
  width: 500px;
1995
1995
  }
1996
1996
 
1997
- .w-\[96px\] {
1998
- width: 96px;
1999
- }
2000
-
2001
1997
  .w-full {
2002
1998
  width: 100%;
2003
1999
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raketa-cloud/admin",
3
- "version": "1.9.4",
3
+ "version": "1.9.5",
4
4
  "main": "src/index.js",
5
5
  "files": [
6
6
  "src/",
@@ -137,6 +137,17 @@ export default class RaketaClient {
137
137
  return { ...result };
138
138
  }
139
139
 
140
+ formatLocaleErrors(localeErrors) {
141
+ if (!localeErrors || !Array.isArray(localeErrors)) {
142
+ return [];
143
+ }
144
+
145
+ return localeErrors.map((item) => ({
146
+ locale: item.locale,
147
+ errors: this.formatErrors(item.errors || []),
148
+ }));
149
+ }
150
+
140
151
  buildFiltersInput(query) {
141
152
  if (!query) {
142
153
  return {};
@@ -7,11 +7,11 @@ import {
7
7
  CreateResourceDocument,
8
8
  DeleteResourceDocument,
9
9
  MiniResourcesDocument,
10
+ MultiTranslateResourceDocument,
10
11
  ResourceByIdDocument,
11
12
  ResourceChangePreviewDocument,
12
13
  ResourcesDocument,
13
14
  TranslateResourceDocument,
14
- buildBatchTranslateResourceDocument,
15
15
  } from "./documents/resourcesDocuments";
16
16
 
17
17
  const SETTINGS_DATE_DEFAULTS = {
@@ -178,43 +178,97 @@ export default class Resources extends RaketaClient {
178
178
  }
179
179
  }
180
180
 
181
- async translateBatch(
181
+ async multiTranslate(
182
182
  sourceResourceId,
183
183
  locales,
184
184
  params,
185
185
  resourceType,
186
186
  workflow,
187
+ sourceLocale,
187
188
  ) {
188
189
  const paramsCopy = { ...params, resourceType };
189
190
  paramsCopy.widgets = JSON.stringify(paramsCopy.widgets);
190
191
  paramsCopy.settings = JSON.stringify(paramsCopy.settings);
191
192
 
192
- const BatchTranslateDocument = buildBatchTranslateResourceDocument(
193
- locales.length,
194
- );
193
+ const translations = locales.map((locale) => ({
194
+ locale,
195
+ resource: paramsCopy,
196
+ }));
195
197
 
196
- const variables = {};
197
- locales.forEach((locale, i) => {
198
- const input = {
199
- locale,
200
- sourceResourceId,
201
- resource: paramsCopy,
198
+ const input = {
199
+ sourceResourceId,
200
+ translations,
201
+ };
202
+
203
+ if (workflow?.type) {
204
+ input.workflow = {
205
+ type: workflow.type,
206
+ previewUrl: buildMagicPreviewAddress(
207
+ {
208
+ slug: paramsCopy.slug,
209
+ locale: sourceLocale || locales[0],
210
+ resourceType,
211
+ },
212
+ this.getConfig(),
213
+ ),
202
214
  };
203
215
 
204
- this.appendWorkflow(input, workflow);
216
+ if (workflow.due_date) {
217
+ input.workflow.dueDate = toUTCISO8601String(workflow.due_date);
218
+ }
219
+ }
205
220
 
206
- variables[`input${i}`] = input;
207
- });
221
+ const {
222
+ multiTranslateResource: { resources, errors, localeErrors },
223
+ } = await this.query(MultiTranslateResourceDocument, { input });
208
224
 
209
- const response = await this.query(BatchTranslateDocument, variables);
225
+ return { resources, errors, localeErrors };
226
+ }
210
227
 
211
- return locales.map((_, i) => {
212
- const result = response[`translate${i}`];
213
- return {
214
- resource: result.resource,
215
- errors: result.errors,
216
- };
217
- });
228
+ async translateBatch(
229
+ sourceResourceId,
230
+ locales,
231
+ params,
232
+ resourceType,
233
+ workflow,
234
+ sourceLocale,
235
+ ) {
236
+ const { resources, errors, localeErrors } = await this.multiTranslate(
237
+ sourceResourceId,
238
+ locales,
239
+ params,
240
+ resourceType,
241
+ workflow,
242
+ sourceLocale,
243
+ );
244
+
245
+ if (localeErrors && localeErrors.length > 0) {
246
+ const localeErrorMap = {};
247
+ localeErrors.forEach((le) => {
248
+ localeErrorMap[le.locale] = le.errors;
249
+ });
250
+
251
+ return locales.map((locale) => ({
252
+ resource: null,
253
+ errors: localeErrorMap[locale] || errors || null,
254
+ }));
255
+ }
256
+
257
+ if (errors) {
258
+ return locales.map(() => ({
259
+ resource: null,
260
+ errors,
261
+ }));
262
+ }
263
+
264
+ if (!resources) {
265
+ return null;
266
+ }
267
+
268
+ return locales.map((_, i) => ({
269
+ resource: resources[i],
270
+ errors: null,
271
+ }));
218
272
  }
219
273
 
220
274
  async updateSlug(id, slug, locale, resourceType, redirect) {
@@ -15,7 +15,7 @@ export const ContentTasksDocument = gql`
15
15
  failedAt
16
16
  insertedAt
17
17
  updatedAt
18
- resource {
18
+ resources {
19
19
  id
20
20
  title
21
21
  slug
@@ -195,22 +195,16 @@ const TranslateResourceDocument = gql`
195
195
  }
196
196
  `;
197
197
 
198
- const buildBatchTranslateResourceDocument = (count) => gql`
199
- mutation BatchTranslateResources(${Array(count)
200
- .fill(0)
201
- .map((_, i) => `$input${i}: TranslateResourceInput!`)
202
- .join(", ")}) {
203
- ${Array(count)
204
- .fill(0)
205
- .map(
206
- (_, i) => `
207
- translate${i}: translateResource(input: $input${i}) {
208
- resource ${resourceFragment()}
198
+ const MultiTranslateResourceDocument = gql`
199
+ mutation MultiTranslateResource($input: MultiTranslateResourceInput!) {
200
+ multiTranslateResource(input: $input) {
201
+ resources ${resourceFragment()}
202
+ errors ${errorsFragment()}
203
+ localeErrors {
204
+ locale
209
205
  errors ${errorsFragment()}
210
206
  }
211
- `,
212
- )
213
- .join("\n")}
207
+ }
214
208
  }
215
209
  `;
216
210
 
@@ -365,6 +359,7 @@ export {
365
359
  DeleteResourceDocument,
366
360
  ResourceAndSiteDocument,
367
361
  TranslateResourceDocument,
362
+ MultiTranslateResourceDocument,
368
363
  ResourceRevisionDocument,
369
364
  ResourceRevisionsDocument,
370
365
  StartResourceRevisionDocument,
@@ -375,7 +370,6 @@ export {
375
370
  ReopenResourceChangeDocument,
376
371
  LockResourceRevisionDocument,
377
372
  UnlockResourceRevisionDocument,
378
- buildBatchTranslateResourceDocument,
379
373
  ResourceHistoryDocument,
380
374
  buildBatchStartResourceRevisionDocument,
381
375
  ResourceEditorsDocument,
@@ -128,7 +128,7 @@ const create = async (ctx) => {
128
128
  : [ctx.resourceParams.resource.languages].filter(Boolean);
129
129
 
130
130
  const existingTranslations = Object.keys(blueprint.translations || {});
131
- const selectedLocales = formLanguages.filter(
131
+ const selectedLocales = [...new Set(formLanguages)].filter(
132
132
  (locale) =>
133
133
  locale !== originalLocale && !existingTranslations.includes(locale),
134
134
  );
@@ -153,15 +153,52 @@ const create = async (ctx) => {
153
153
 
154
154
  const workflow = ctx.resourceParams?.resource?.workflow;
155
155
 
156
- const translations = await ctx.client.resources.translateBatch(
157
- parent_id,
158
- selectedLocales,
159
- resource,
160
- resourceType,
161
- workflow,
162
- );
156
+ const { resources, errors, localeErrors } =
157
+ await ctx.client.resources.multiTranslate(
158
+ parent_id,
159
+ selectedLocales,
160
+ resource,
161
+ resourceType,
162
+ workflow,
163
+ originalLocale,
164
+ );
165
+
166
+ if (localeErrors && localeErrors.length > 0) {
167
+ return {
168
+ assigns: {
169
+ resource: {
170
+ ...resource,
171
+ translations: blueprint.translations || {},
172
+ languages: formLanguages,
173
+ workflow: workflow,
174
+ },
175
+ blueprint,
176
+ targetLocale: originalLocale,
177
+ errors: {
178
+ resource: errors ? ctx.client.resources.formatErrors(errors) : {},
179
+ localeErrors: ctx.client.resources.formatLocaleErrors(localeErrors),
180
+ },
181
+ },
182
+ };
183
+ }
184
+
185
+ if (errors) {
186
+ return {
187
+ assigns: {
188
+ resource: {
189
+ ...resource,
190
+ translations: blueprint.translations || {},
191
+ languages: formLanguages,
192
+ workflow: workflow,
193
+ },
194
+ blueprint,
195
+ targetLocale: originalLocale,
196
+ errors: { resource: ctx.client.resources.formatErrors(errors) },
197
+ },
198
+ };
199
+ }
163
200
 
164
- if (!translations) {
201
+ if (!resources) {
165
202
  return {
166
203
  assigns: {
167
204
  resource: {
@@ -184,8 +221,10 @@ const create = async (ctx) => {
184
221
  };
185
222
  }
186
223
 
187
- for (let i = 0; i < translations.length; i++) {
188
- const { resource: translated } = translations[i];
224
+ const revisionInputs = [];
225
+
226
+ for (let i = 0; i < resources.length; i++) {
227
+ const translated = resources[i];
189
228
  const locale = selectedLocales[i];
190
229
 
191
230
  if (translated) {
@@ -197,32 +236,7 @@ const create = async (ctx) => {
197
236
  visibility: translated.visibility,
198
237
  },
199
238
  };
200
- }
201
- }
202
-
203
- const revisionInputs = [];
204
-
205
- for (let i = 0; i < translations.length; i++) {
206
- const { errors, resource: translated } = translations[i];
207
- const locale = selectedLocales[i];
208
239
 
209
- if (errors) {
210
- return {
211
- assigns: {
212
- resource: {
213
- ...resource,
214
- translations: blueprint.translations || {},
215
- languages: formLanguages,
216
- workflow: workflow,
217
- },
218
- blueprint,
219
- targetLocale: locale,
220
- errors: { resource: ctx.client.resources.formatErrors(errors) },
221
- },
222
- };
223
- }
224
-
225
- if (translated) {
226
240
  translationIds.push(`${locale}:${translated.id}`);
227
241
  revisionInputs.push({
228
242
  resourceId: translated.id,
@@ -247,7 +261,7 @@ const create = async (ctx) => {
247
261
  languages: formLanguages,
248
262
  },
249
263
  blueprint,
250
- targetLocale: selectedLocales[i],
264
+ targetLocale: revisionInputs[i]?.locale || selectedLocales[i],
251
265
  errors: {
252
266
  resource: ctx.client.resources.formatErrors(revisionErrors),
253
267
  },
@@ -232,6 +232,46 @@ describe("RaketaClient", () => {
232
232
  });
233
233
  });
234
234
 
235
+ describe("formatLocaleErrors", () => {
236
+ test("formats array of locale errors", () => {
237
+ const client = buildClient();
238
+ const localeErrors = [
239
+ {
240
+ locale: "fr",
241
+ errors: [{ key: "title", message: "Title is required" }],
242
+ },
243
+ {
244
+ locale: "de",
245
+ errors: [
246
+ { key: "slug", message: "Slug is taken" },
247
+ { key: "slug", message: "Slug is invalid" },
248
+ ],
249
+ },
250
+ ];
251
+
252
+ const result = client.formatLocaleErrors(localeErrors);
253
+
254
+ expect(result).toEqual([
255
+ {
256
+ locale: "fr",
257
+ errors: { title: "Title is required" },
258
+ },
259
+ {
260
+ locale: "de",
261
+ errors: { slug: "Slug is taken, Slug is invalid" },
262
+ },
263
+ ]);
264
+ });
265
+
266
+ test("returns empty array for invalid input", () => {
267
+ const client = buildClient();
268
+
269
+ expect(client.formatLocaleErrors(null)).toEqual([]);
270
+ expect(client.formatLocaleErrors(undefined)).toEqual([]);
271
+ expect(client.formatLocaleErrors({})).toEqual([]);
272
+ });
273
+ });
274
+
235
275
  describe("buildFiltersInput", () => {
236
276
  test("extracts filters with f: prefix", () => {
237
277
  const client = buildClient();
@@ -26,22 +26,26 @@ describe("ContentTasksHandler", () => {
26
26
  Factory.build("contentTask", {
27
27
  id: "1",
28
28
  workflow: "lokalise",
29
- resource: {
30
- id: "123",
31
- title: "Test Page",
32
- locale: "en",
33
- resourceType: "page",
34
- },
29
+ resources: [
30
+ {
31
+ id: "123",
32
+ title: "Test Page",
33
+ locale: "en",
34
+ resourceType: "page",
35
+ },
36
+ ],
35
37
  }),
36
38
  Factory.build("contentTask", {
37
39
  id: "2",
38
40
  workflow: "default",
39
- resource: {
40
- id: "456",
41
- title: "Test Movie",
42
- locale: "de",
43
- resourceType: "movie-type",
44
- },
41
+ resources: [
42
+ {
43
+ id: "456",
44
+ title: "Test Movie",
45
+ locale: "de",
46
+ resourceType: "movie-type",
47
+ },
48
+ ],
45
49
  }),
46
50
  ];
47
51