@raketa-cloud/admin 1.8.13 → 1.8.15

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.
@@ -1566,12 +1566,8 @@ select {
1566
1566
  pointer-events: none;
1567
1567
  }
1568
1568
 
1569
- .static {
1570
- position: static;
1571
- }
1572
-
1573
- .fixed {
1574
- position: fixed;
1569
+ .visible {
1570
+ visibility: visible;
1575
1571
  }
1576
1572
 
1577
1573
  .absolute {
@@ -1737,10 +1733,6 @@ select {
1737
1733
  display: inline-block;
1738
1734
  }
1739
1735
 
1740
- .inline {
1741
- display: inline;
1742
- }
1743
-
1744
1736
  .flex {
1745
1737
  display: flex;
1746
1738
  }
@@ -1976,6 +1968,12 @@ select {
1976
1968
  overflow-y: auto;
1977
1969
  }
1978
1970
 
1971
+ .truncate {
1972
+ overflow: hidden;
1973
+ text-overflow: ellipsis;
1974
+ white-space: nowrap;
1975
+ }
1976
+
1979
1977
  .whitespace-nowrap {
1980
1978
  white-space: nowrap;
1981
1979
  }
@@ -2337,6 +2335,12 @@ select {
2337
2335
  opacity: 0.75;
2338
2336
  }
2339
2337
 
2338
+ .shadow {
2339
+ --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
2340
+ --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
2341
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
2342
+ }
2343
+
2340
2344
  .shadow-inner {
2341
2345
  --tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
2342
2346
  --tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raketa-cloud/admin",
3
- "version": "1.8.13",
3
+ "version": "1.8.15",
4
4
  "main": "src/index.js",
5
5
  "files": [
6
6
  "src/",
@@ -21,13 +21,17 @@
21
21
  "@tailwindcss/forms": "0.5.7",
22
22
  "@tailwindcss/typography": "0.5.13",
23
23
  "@types/node": "24.10.1",
24
- "jest": "30.3.0",
24
+ "babel-jest": "^29.7.0",
25
+ "jest": "^29.7.0",
26
+ "jest-environment-node": "^29.7.0",
25
27
  "tailwindcss": "3.4.4",
26
28
  "typescript": "5.9.3"
27
29
  },
28
30
  "dependencies": {
29
- "ejs": "3.1.10",
30
- "graphql-request": "7.4.0"
31
+ "@hono/node-server": "2.0.12",
32
+ "ejs": "^6.0.1",
33
+ "graphql-request": "7.4.0",
34
+ "hono": "4.12.32"
31
35
  },
32
36
  "overrides": {
33
37
  "error-ex": "1.3.4"
@@ -111,7 +111,6 @@ export function contentTaskFragment() {
111
111
  operatorMeta
112
112
  completedAt
113
113
  failedAt
114
- rejectedAt
115
114
  insertedAt
116
115
  updatedAt
117
116
  }
@@ -13,7 +13,6 @@ export const ContentTasksDocument = gql`
13
13
  operatorMeta
14
14
  completedAt
15
15
  failedAt
16
- rejectedAt
17
16
  insertedAt
18
17
  updatedAt
19
18
  resource {
@@ -21,6 +21,7 @@ function minimalResourceFragment() {
21
21
  insertedAt
22
22
  updatedAt
23
23
  translations
24
+ tags ${tagFragment()}
24
25
  }
25
26
  `;
26
27
  }
@@ -50,7 +51,6 @@ function resourceFragment() {
50
51
  operatorMeta
51
52
  completedAt
52
53
  failedAt
53
- rejectedAt
54
54
  insertedAt
55
55
  updatedAt
56
56
  }
@@ -75,6 +75,10 @@ function formatTranslations(item) {
75
75
  .join(";");
76
76
  }
77
77
 
78
+ function formatTags(item) {
79
+ return (item?.tags || []).map((tag) => tag.name).join(";");
80
+ }
81
+
78
82
  const standardFieldMapping = (remoteConfig, locale, type) => ({
79
83
  id: "id",
80
84
  type: (item) => extractResourceType(item, type),
@@ -85,6 +89,7 @@ const standardFieldMapping = (remoteConfig, locale, type) => ({
85
89
  created_at: "insertedAt",
86
90
  updated_at: "updatedAt",
87
91
  translations: formatTranslations,
92
+ tags: formatTags,
88
93
  });
89
94
 
90
95
  const standardHeaders = [
@@ -97,6 +102,7 @@ const standardHeaders = [
97
102
  "created_at",
98
103
  "updated_at",
99
104
  "translations",
105
+ "tags",
100
106
  ];
101
107
 
102
108
  export default {
@@ -144,7 +144,7 @@ describe("Resources ExportsHandler", () => {
144
144
  const result = await ExportsHandler.index(ctx);
145
145
 
146
146
  expect(result.text).toBe(
147
- "id,type,locale,title,URL,visibility,created_at,updated_at,translations",
147
+ "id,type,locale,title,URL,visibility,created_at,updated_at,translations,tags",
148
148
  );
149
149
  });
150
150
 
@@ -210,6 +210,7 @@ describe("CSVExportHelper", () => {
210
210
  es: {},
211
211
  de: {},
212
212
  },
213
+ tags: [{ name: "Finance" }, { name: "Product" }],
213
214
  },
214
215
  ];
215
216
  const headers = [...CSVExportHelper.standardHeaders];
@@ -226,8 +227,8 @@ describe("CSVExportHelper", () => {
226
227
  );
227
228
 
228
229
  expect(result).toBe(
229
- "id,type,locale,title,URL,visibility,created_at,updated_at,translations\r\n" +
230
- "1,article,en,Test Article,/en/article/1,public,2024-01-01,2024-01-02,es;de",
230
+ "id,type,locale,title,URL,visibility,created_at,updated_at,translations,tags\r\n" +
231
+ "1,article,en,Test Article,/en/article/1,public,2024-01-01,2024-01-02,es;de,Finance;Product",
231
232
  );
232
233
  });
233
234
  });
@@ -302,6 +303,7 @@ describe("CSVExportHelper", () => {
302
303
  created_at: "insertedAt",
303
304
  updated_at: "updatedAt",
304
305
  translations: expect.any(Function),
306
+ tags: expect.any(Function),
305
307
  });
306
308
  });
307
309
 
@@ -364,6 +366,7 @@ describe("CSVExportHelper", () => {
364
366
  "created_at",
365
367
  "updated_at",
366
368
  "translations",
369
+ "tags",
367
370
  ]);
368
371
  });
369
372
  });
@@ -85,7 +85,6 @@ const CONTENT_TASK = {
85
85
  },
86
86
  completedAt: null,
87
87
  failedAt: null,
88
- rejectedAt: null,
89
88
  insertedAt: "2024-08-30T19:05:00Z",
90
89
  updatedAt: "2024-08-30T19:05:00Z",
91
90
  resource: {
@@ -76,14 +76,14 @@
76
76
  </td>
77
77
 
78
78
  <td>
79
- <% if (task.completedAt || task.failedAt || task.rejectedAt) { %>
79
+ <% if (task.completedAt || task.failedAt) { %>
80
80
  <div class="body-3 text-raketa-foreground/50">
81
81
  <div class="flex items-center gap-1">
82
82
  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4 text-raketa-foreground">
83
83
  <path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
84
84
  </svg>
85
- <time data-pretty-datetime datetime="<%= task.completedAt || task.failedAt || task.rejectedAt %>">
86
- <%= utils.formattedDateTime(task.completedAt || task.failedAt || task.rejectedAt) %>
85
+ <time data-pretty-datetime datetime="<%= task.completedAt || task.failedAt %>">
86
+ <%= utils.formattedDateTime(task.completedAt || task.failedAt) %>
87
87
  </time>
88
88
  </div>
89
89
  </div>
@@ -101,10 +101,6 @@
101
101
  <span class="bg-red-100 chip text-red-700 dark:bg-red-900/50 dark:text-red-300">
102
102
  Failed
103
103
  </span>
104
- <% } else if (task.rejectedAt) { %>
105
- <span class="bg-orange-100 chip text-orange-700 dark:bg-orange-900/50 dark:text-orange-300">
106
- Rejected
107
- </span>
108
104
  <% } else { %>
109
105
  <span class="bg-blue-100 chip text-blue-700 dark:bg-blue-900/50 dark:text-blue-300">
110
106
  In Progress
@@ -3,8 +3,7 @@
3
3
  const hasActiveContentTask = utils.feature("contentTasks", _context) &&
4
4
  resource.activeContentTask &&
5
5
  !resource.activeContentTask.completedAt &&
6
- !resource.activeContentTask.failedAt &&
7
- !resource.activeContentTask.rejectedAt;
6
+ !resource.activeContentTask.failedAt;
8
7
  %>
9
8
  <div class="actions-toolbar">
10
9
  <form method="POST" action="<%= `/${_context.locale}/${_context.resourceConfig.resourceTypePlural}/${resource.id}/${_context.resourceConfig.resourceType}_revisions` %>" class="inline-block">
@@ -13,8 +13,7 @@
13
13
  const currentHasActiveTask = utils.feature("contentTasks", _context) &&
14
14
  resource.activeContentTask &&
15
15
  !resource.activeContentTask.completedAt &&
16
- !resource.activeContentTask.failedAt &&
17
- !resource.activeContentTask.rejectedAt;
16
+ !resource.activeContentTask.failedAt;
18
17
 
19
18
  const contentTaskMessage = currentHasActiveTask ? `${name}: ${Inflector.capitalize(resource.activeContentTask.workflow)} task in progress` : '';
20
19
  %>
@@ -40,7 +40,7 @@
40
40
  <% if (item.revisionsCount > 0) { %>
41
41
  <span class="bg-orange-100 chip text-orange-700 dark:bg-orange-900/50 dark:text-orange-300"><%= item.revisionsCount !== 1 ? `${item.revisionsCount} open revisions` : 'Open revision' %></span>
42
42
  <% } %>
43
- <% if (utils.feature("contentTasks", _context) && item.activeContentTask && !item.activeContentTask.completedAt && !item.activeContentTask.failedAt && !item.activeContentTask.rejectedAt) { %>
43
+ <% if (utils.feature("contentTasks", _context) && item.activeContentTask && !item.activeContentTask.completedAt && !item.activeContentTask.failedAt) { %>
44
44
  <span class="bg-blue-100 chip text-blue-700 dark:bg-blue-900/50 dark:text-blue-300" title="<%= item.activeContentTask.workflow ? `${item.activeContentTask.workflow} workflow` : 'Translation in progress' %>">
45
45
  Content task in progress
46
46
  </span>
@@ -35,7 +35,9 @@
35
35
  <label for="workflow" class="font-semibold hover:cursor-pointer body-3">Translation workflow</label>
36
36
  <select name="resource[workflow]" id="workflow">
37
37
  <option value="">Default (no workflow)</option>
38
- <option value="lokalise" <%= resource.workflow === 'lokalise' ? 'selected' : '' %>>Lokalise workflow</option>
38
+ <option value="LOKALISE_TO_AI_RT_HUM" <%= resource.workflow === 'LOKALISE_TO_AI_RT_HUM' ? 'selected' : '' %>>Lokalise: AI translation & Human review</option>
39
+ <option value="LOKALISE_TT_HUM" <%= resource.workflow === 'LOKALISE_TT_HUM' ? 'selected' : '' %>>Lokalise: Human translation</option>
40
+ <option value="LOKALISE_TT_AI" <%= resource.workflow === 'LOKALISE_TT_AI' ? 'selected' : '' %>>Lokalise: AI translation</option>
39
41
  </select>
40
42
  <p class="text-sm text-raketa-foreground/50 mt-1">
41
43
  Select a workflow for the translation process. Lokalise workflow initiates a content task for external translation.
@@ -66,23 +68,61 @@
66
68
  <% }) %>
67
69
 
68
70
  <div>
69
- <div class="help">
70
- <div class="flex items-center gap-1 mb-2">
71
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
72
- <path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" />
73
- </svg>
71
+ <% if (utils.feature("contentTasks", _context) && _context.locale === _context.defaultLocale) { %>
72
+
73
+ <div class="help">
74
+ <div class="flex items-center gap-1 mb-2">
75
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
76
+ <path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" />
77
+ </svg>
78
+
79
+ <h3 class="heading-3">Translating <%= Inflector.downcase(_context.resourceConfig.resourceTypePlural) %></h3>
80
+ </div>
74
81
 
75
- <h3 class="heading-3">Translating <%= Inflector.downcase(_context.resourceConfig.resourceTypePlural) %></h3>
82
+ <div class="markdown">
83
+ Select one or multiple locales to initiate bulk translations. The process depends on your selected workflow:
84
+ <br />
85
+ <ol>
86
+ <li>
87
+ <strong>Default (Content Editors):</strong> A private copy and new revision are created immediately. The next screen provides quick links to translate settings and widgets so you can translate the content manually.
88
+ </li>
89
+ <li>
90
+ <strong>AI Translation (Lokalise):</strong> A task is sent to Lokalise Pro AI to automatically translate the content.
91
+ </li>
92
+ <li>
93
+ <strong>AI + Human Review (Lokalise):</strong> A task is sent to Lokalise where an AI translates the content, which then awaits human review.
94
+ </li>
95
+ <li>
96
+ <strong>Human Translation (Lokalise):</strong> A task is sent to Lokalise where a human translator fully translates and reviews the content.
97
+ </li>
98
+ </ol>
99
+
100
+ <br />
101
+ <strong>Note:</strong> For all Lokalise workflows (<strong>AI, AI + Human</strong>, and <strong>Human</strong>), the private copy and new revision will be automatically created here in the CMS only after the external task is completed and returned.
102
+ </div>
76
103
  </div>
77
104
 
78
- <div class="markdown">
79
- <ol>
80
- <li>Select multiple locales to initiate bulk translations.</li>
81
- <li>A private copy of the <%= Inflector.downcase(_context.resourceConfig.resourceType) %> will be automatically created for each selected language, with a new revision opened to facilitate the translation process.</li>
82
- <li>On the next screen you'll see a list with quick links to transalte settings and widgets</li>
83
- </ol>
105
+ <% } else { %>
106
+
107
+ <div class="help">
108
+ <div class="flex items-center gap-1 mb-2">
109
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
110
+ <path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" />
111
+ </svg>
112
+
113
+ <h3 class="heading-3">Translating <%= Inflector.downcase(_context.resourceConfig.resourceTypePlural) %></h3>
114
+ </div>
115
+
116
+ <div class="markdown">
117
+ <ol>
118
+ <li>Select multiple locales to initiate bulk translations.</li>
119
+ <li>A private copy of the <%= Inflector.downcase(_context.resourceConfig.resourceType) %> will be automatically created for each selected language, with a new revision opened to facilitate the translation process.</li>
120
+ <li>On the next screen you'll see a list with quick links to transalte settings and widgets.</li>
121
+ </ol>
122
+ </div>
84
123
  </div>
85
- </div>
124
+
125
+ <% } %>
86
126
  </div>
87
127
  </div>
88
128
  </div>