@raketa-cloud/admin 1.9.4 → 1.9.6
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.
- package/dist/application.css +3 -41
- package/package.json +2 -2
- package/src/cloud/RaketaClient.js +11 -0
- package/src/cloud/Resources.js +68 -26
- package/src/cloud/documents/contentTasksDocuments.js +1 -1
- package/src/cloud/documents/resourcesDocuments.js +10 -25
- package/src/handlers/resources/TranslationsHandler.js +51 -37
- package/src/magicPreview.js +66 -9
- package/src/tests/RaketaClient.test.js +40 -0
- package/src/tests/handlers/content_tasks/ContentTasksHandler.test/index.test.js +16 -12
- package/src/tests/handlers/resources/TranslationsHandler.test/create.test.js +127 -71
- package/src/tests/handlers/resources/TranslationsHandler.test/edge_cases.test.js +51 -8
- package/src/tests/magicPreview.test.js +79 -0
- package/src/tests/support/factory.js +12 -10
- package/src/views/_auth/login.ejs +11 -31
- package/src/views/_shared/_content_tasks.ejs +43 -11
- package/src/views/layouts/header.ejs +4 -5
- package/src/views/resources/show.ejs +1 -1
- package/src/views/resources/translations/create_form.ejs +19 -3
- package/src/views/resources/translations/index.ejs +3 -7
package/dist/application.css
CHANGED
|
@@ -749,40 +749,6 @@ select {
|
|
|
749
749
|
--tw-contain-style: ;
|
|
750
750
|
}
|
|
751
751
|
|
|
752
|
-
.container {
|
|
753
|
-
width: 100%;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
@media (min-width: 640px) {
|
|
757
|
-
.container {
|
|
758
|
-
max-width: 640px;
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
@media (min-width: 768px) {
|
|
763
|
-
.container {
|
|
764
|
-
max-width: 768px;
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
@media (min-width: 1024px) {
|
|
769
|
-
.container {
|
|
770
|
-
max-width: 1024px;
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
@media (min-width: 1280px) {
|
|
775
|
-
.container {
|
|
776
|
-
max-width: 1280px;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
@media (min-width: 1536px) {
|
|
781
|
-
.container {
|
|
782
|
-
max-width: 1536px;
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
752
|
/* Utils */
|
|
787
753
|
|
|
788
754
|
.chip {
|
|
@@ -1862,9 +1828,9 @@ select {
|
|
|
1862
1828
|
height: 3rem;
|
|
1863
1829
|
}
|
|
1864
1830
|
|
|
1865
|
-
.size-
|
|
1866
|
-
width:
|
|
1867
|
-
height:
|
|
1831
|
+
.size-16 {
|
|
1832
|
+
width: 4rem;
|
|
1833
|
+
height: 4rem;
|
|
1868
1834
|
}
|
|
1869
1835
|
|
|
1870
1836
|
.size-3 {
|
|
@@ -1994,10 +1960,6 @@ select {
|
|
|
1994
1960
|
width: 500px;
|
|
1995
1961
|
}
|
|
1996
1962
|
|
|
1997
|
-
.w-\[96px\] {
|
|
1998
|
-
width: 96px;
|
|
1999
|
-
}
|
|
2000
|
-
|
|
2001
1963
|
.w-full {
|
|
2002
1964
|
width: 100%;
|
|
2003
1965
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raketa-cloud/admin",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.6",
|
|
4
4
|
"main": "src/index.js",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"chart.js": "4.5.1",
|
|
38
38
|
"ejs": "6.0.1",
|
|
39
39
|
"graphql-request": "7.4.0",
|
|
40
|
-
"hono": "4.
|
|
40
|
+
"hono": "4.13.7",
|
|
41
41
|
"lru-cache": "11.5.2"
|
|
42
42
|
},
|
|
43
43
|
"overrides": {
|
|
@@ -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 {};
|
package/src/cloud/Resources.js
CHANGED
|
@@ -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 = {
|
|
@@ -156,7 +156,7 @@ export default class Resources extends RaketaClient {
|
|
|
156
156
|
return { resource, errors };
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
appendWorkflow(input, workflow) {
|
|
159
|
+
appendWorkflow(input, workflow, previewParams = {}) {
|
|
160
160
|
if (!workflow?.type) {
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
@@ -165,9 +165,9 @@ export default class Resources extends RaketaClient {
|
|
|
165
165
|
type: workflow.type,
|
|
166
166
|
previewUrl: buildMagicPreviewAddress(
|
|
167
167
|
{
|
|
168
|
-
slug:
|
|
169
|
-
locale:
|
|
170
|
-
resourceType:
|
|
168
|
+
slug: previewParams.slug,
|
|
169
|
+
locale: previewParams.locale,
|
|
170
|
+
resourceType: previewParams.resourceType,
|
|
171
171
|
},
|
|
172
172
|
this.getConfig(),
|
|
173
173
|
),
|
|
@@ -178,43 +178,85 @@ export default class Resources extends RaketaClient {
|
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
async
|
|
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
|
|
193
|
-
|
|
193
|
+
const translations = locales.map((locale) => ({
|
|
194
|
+
locale,
|
|
195
|
+
resource: paramsCopy,
|
|
196
|
+
}));
|
|
197
|
+
|
|
198
|
+
const input = {
|
|
199
|
+
sourceResourceId,
|
|
200
|
+
translations,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
this.appendWorkflow(input, workflow, {
|
|
204
|
+
slug: paramsCopy.slug,
|
|
205
|
+
locale: sourceLocale,
|
|
206
|
+
resourceType,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const {
|
|
210
|
+
multiTranslateResource: { resources, errors, localeErrors },
|
|
211
|
+
} = await this.query(MultiTranslateResourceDocument, { input });
|
|
212
|
+
|
|
213
|
+
return { resources, errors, localeErrors };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async translateBatch(
|
|
217
|
+
sourceResourceId,
|
|
218
|
+
locales,
|
|
219
|
+
params,
|
|
220
|
+
resourceType,
|
|
221
|
+
workflow,
|
|
222
|
+
sourceLocale,
|
|
223
|
+
) {
|
|
224
|
+
const { resources, errors, localeErrors } = await this.multiTranslate(
|
|
225
|
+
sourceResourceId,
|
|
226
|
+
locales,
|
|
227
|
+
params,
|
|
228
|
+
resourceType,
|
|
229
|
+
workflow,
|
|
230
|
+
sourceLocale,
|
|
194
231
|
);
|
|
195
232
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
locale
|
|
200
|
-
|
|
201
|
-
resource: paramsCopy,
|
|
202
|
-
};
|
|
233
|
+
if (localeErrors && localeErrors.length > 0) {
|
|
234
|
+
const localeErrorMap = {};
|
|
235
|
+
localeErrors.forEach((le) => {
|
|
236
|
+
localeErrorMap[le.locale] = le.errors;
|
|
237
|
+
});
|
|
203
238
|
|
|
204
|
-
|
|
239
|
+
return locales.map((locale) => ({
|
|
240
|
+
resource: null,
|
|
241
|
+
errors: localeErrorMap[locale] || errors || null,
|
|
242
|
+
}));
|
|
243
|
+
}
|
|
205
244
|
|
|
206
|
-
|
|
207
|
-
|
|
245
|
+
if (errors) {
|
|
246
|
+
return locales.map(() => ({
|
|
247
|
+
resource: null,
|
|
248
|
+
errors,
|
|
249
|
+
}));
|
|
250
|
+
}
|
|
208
251
|
|
|
209
|
-
|
|
252
|
+
if (!resources) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
210
255
|
|
|
211
|
-
return locales.map((_, i) => {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
errors: result.errors,
|
|
216
|
-
};
|
|
217
|
-
});
|
|
256
|
+
return locales.map((_, i) => ({
|
|
257
|
+
resource: resources[i],
|
|
258
|
+
errors: null,
|
|
259
|
+
}));
|
|
218
260
|
}
|
|
219
261
|
|
|
220
262
|
async updateSlug(id, slug, locale, resourceType, redirect) {
|
|
@@ -44,16 +44,7 @@ function resourceFragment() {
|
|
|
44
44
|
tags ${tagFragment()}
|
|
45
45
|
categories ${categoryFragment()}
|
|
46
46
|
changes ${summaryChangeFragment()}
|
|
47
|
-
activeContentTask {
|
|
48
|
-
id
|
|
49
|
-
workflow
|
|
50
|
-
operator
|
|
51
|
-
operatorMeta
|
|
52
|
-
completedAt
|
|
53
|
-
failedAt
|
|
54
|
-
insertedAt
|
|
55
|
-
updatedAt
|
|
56
|
-
}
|
|
47
|
+
activeContentTask ${contentTaskFragment()}
|
|
57
48
|
}
|
|
58
49
|
`;
|
|
59
50
|
}
|
|
@@ -195,22 +186,16 @@ const TranslateResourceDocument = gql`
|
|
|
195
186
|
}
|
|
196
187
|
`;
|
|
197
188
|
|
|
198
|
-
const
|
|
199
|
-
mutation
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
.map(
|
|
206
|
-
(_, i) => `
|
|
207
|
-
translate${i}: translateResource(input: $input${i}) {
|
|
208
|
-
resource ${resourceFragment()}
|
|
189
|
+
const MultiTranslateResourceDocument = gql`
|
|
190
|
+
mutation MultiTranslateResource($input: MultiTranslateResourceInput!) {
|
|
191
|
+
multiTranslateResource(input: $input) {
|
|
192
|
+
resources ${resourceFragment()}
|
|
193
|
+
errors ${errorsFragment()}
|
|
194
|
+
localeErrors {
|
|
195
|
+
locale
|
|
209
196
|
errors ${errorsFragment()}
|
|
210
197
|
}
|
|
211
|
-
|
|
212
|
-
)
|
|
213
|
-
.join("\n")}
|
|
198
|
+
}
|
|
214
199
|
}
|
|
215
200
|
`;
|
|
216
201
|
|
|
@@ -365,6 +350,7 @@ export {
|
|
|
365
350
|
DeleteResourceDocument,
|
|
366
351
|
ResourceAndSiteDocument,
|
|
367
352
|
TranslateResourceDocument,
|
|
353
|
+
MultiTranslateResourceDocument,
|
|
368
354
|
ResourceRevisionDocument,
|
|
369
355
|
ResourceRevisionsDocument,
|
|
370
356
|
StartResourceRevisionDocument,
|
|
@@ -375,7 +361,6 @@ export {
|
|
|
375
361
|
ReopenResourceChangeDocument,
|
|
376
362
|
LockResourceRevisionDocument,
|
|
377
363
|
UnlockResourceRevisionDocument,
|
|
378
|
-
buildBatchTranslateResourceDocument,
|
|
379
364
|
ResourceHistoryDocument,
|
|
380
365
|
buildBatchStartResourceRevisionDocument,
|
|
381
366
|
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
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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 (!
|
|
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
|
-
|
|
188
|
-
|
|
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
|
},
|
package/src/magicPreview.js
CHANGED
|
@@ -8,9 +8,10 @@ import {
|
|
|
8
8
|
const ALGORITHM = "aes-256-gcm";
|
|
9
9
|
const IV_LENGTH = 12;
|
|
10
10
|
const TAG_LENGTH = 16;
|
|
11
|
+
const CHUNK_SIZE = 40;
|
|
11
12
|
|
|
12
13
|
function getSecretKey(config = {}) {
|
|
13
|
-
const secret = config.secrets
|
|
14
|
+
const secret = config.secrets?.crypto_secret;
|
|
14
15
|
|
|
15
16
|
if (!secret) {
|
|
16
17
|
throw new Error(
|
|
@@ -21,6 +22,40 @@ function getSecretKey(config = {}) {
|
|
|
21
22
|
return createHash("sha256").update(secret).digest();
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
export function chunkToken(token, chunkSize = CHUNK_SIZE) {
|
|
26
|
+
if (!token || typeof token !== "string") {
|
|
27
|
+
return token;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const chunks = [];
|
|
31
|
+
for (let i = 0; i < token.length; i += chunkSize) {
|
|
32
|
+
chunks.push(token.slice(i, i + chunkSize));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return chunks.join("-");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function unchunkToken(token, chunkSize = CHUNK_SIZE) {
|
|
39
|
+
if (!token || typeof token !== "string") {
|
|
40
|
+
return token;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let result = "";
|
|
44
|
+
let i = 0;
|
|
45
|
+
|
|
46
|
+
while (i < token.length) {
|
|
47
|
+
const chunk = token.slice(i, i + chunkSize);
|
|
48
|
+
result += chunk;
|
|
49
|
+
i += chunkSize;
|
|
50
|
+
|
|
51
|
+
if (i < token.length && token[i] === "-") {
|
|
52
|
+
i += 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
|
|
24
59
|
export function generateMagicPreviewToken(
|
|
25
60
|
{ slug, resourceType, locale } = {},
|
|
26
61
|
config = {},
|
|
@@ -40,17 +75,14 @@ export function generateMagicPreviewToken(
|
|
|
40
75
|
]);
|
|
41
76
|
const tag = cipher.getAuthTag();
|
|
42
77
|
|
|
43
|
-
|
|
44
|
-
}
|
|
78
|
+
const rawToken = Buffer.concat([iv, tag, encrypted]).toString("base64url");
|
|
45
79
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
80
|
+
return chunkToken(rawToken);
|
|
81
|
+
}
|
|
50
82
|
|
|
83
|
+
function decipherPayload(rawToken, key) {
|
|
51
84
|
try {
|
|
52
|
-
const
|
|
53
|
-
const combined = Buffer.from(token, "base64url");
|
|
85
|
+
const combined = Buffer.from(rawToken, "base64url");
|
|
54
86
|
|
|
55
87
|
if (combined.length < IV_LENGTH + TAG_LENGTH) {
|
|
56
88
|
return null;
|
|
@@ -80,6 +112,31 @@ export function decipherMagicPreviewToken(token, config) {
|
|
|
80
112
|
}
|
|
81
113
|
}
|
|
82
114
|
|
|
115
|
+
export function decipherMagicPreviewToken(token, config) {
|
|
116
|
+
if (!token || typeof token !== "string") {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const key = getSecretKey(config);
|
|
122
|
+
|
|
123
|
+
const unchunked = unchunkToken(token);
|
|
124
|
+
const payload = decipherPayload(unchunked, key);
|
|
125
|
+
|
|
126
|
+
if (payload) {
|
|
127
|
+
return payload;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (unchunked !== token) {
|
|
131
|
+
return decipherPayload(token, key);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return null;
|
|
135
|
+
} catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
83
140
|
export function buildMagicPreviewAddress(
|
|
84
141
|
{ slug, resourceType, locale },
|
|
85
142
|
globalConfig,
|
|
@@ -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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|