lightnet 3.12.0 → 3.12.1
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/CHANGELOG.md +16 -0
- package/__e2e__/admin.spec.ts +1 -365
- package/__e2e__/fixtures/basics/node_modules/.bin/astro +2 -2
- package/__e2e__/fixtures/basics/package.json +3 -3
- package/package.json +8 -15
- package/src/astro-integration/config.ts +1 -22
- package/src/astro-integration/integration.ts +4 -39
- package/src/content/get-media-items.ts +1 -47
- package/src/i18n/translate.ts +1 -1
- package/src/i18n/translations/TRANSLATION-STATUS.md +37 -12
- package/src/i18n/translations/en.yml +5 -0
- package/src/i18n/translations.ts +0 -7
- package/src/layouts/Page.astro +2 -0
- package/src/layouts/global.css +3 -0
- package/src/pages/details-page/components/main-details/EditButton.astro +2 -4
- package/src/pages/search-page/components/SearchFilter.tsx +1 -1
- package/src/admin/api/fs/write-file.ts +0 -53
- package/src/admin/components/form/DynamicArray.tsx +0 -129
- package/src/admin/components/form/Input.tsx +0 -68
- package/src/admin/components/form/LazyLoadedMarkdownEditor.tsx +0 -109
- package/src/admin/components/form/MarkdownEditor.tsx +0 -62
- package/src/admin/components/form/Select.tsx +0 -71
- package/src/admin/components/form/SubmitButton.tsx +0 -86
- package/src/admin/components/form/atoms/Button.tsx +0 -27
- package/src/admin/components/form/atoms/ErrorMessage.tsx +0 -13
- package/src/admin/components/form/atoms/FileUpload.tsx +0 -190
- package/src/admin/components/form/atoms/Hint.tsx +0 -19
- package/src/admin/components/form/atoms/Label.tsx +0 -37
- package/src/admin/components/form/hooks/use-field-dirty.tsx +0 -12
- package/src/admin/components/form/hooks/use-field-error.tsx +0 -34
- package/src/admin/components/form/utils/get-border-class.ts +0 -22
- package/src/admin/i18n/admin-i18n.ts +0 -21
- package/src/admin/i18n/translations/en.yml +0 -50
- package/src/admin/i18n/translations.ts +0 -5
- package/src/admin/pages/AdminRoute.astro +0 -14
- package/src/admin/pages/media/EditForm.tsx +0 -136
- package/src/admin/pages/media/EditRoute.astro +0 -100
- package/src/admin/pages/media/fields/Authors.tsx +0 -44
- package/src/admin/pages/media/fields/Categories.tsx +0 -49
- package/src/admin/pages/media/fields/Collections.tsx +0 -68
- package/src/admin/pages/media/fields/Content.tsx +0 -150
- package/src/admin/pages/media/fields/Image.tsx +0 -119
- package/src/admin/pages/media/file-system.ts +0 -41
- package/src/admin/pages/media/media-item-store.ts +0 -61
- package/src/admin/types/media-item.ts +0 -81
- package/src/api/media/[mediaId].ts +0 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# lightnet
|
|
2
2
|
|
|
3
|
+
## 3.12.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#356](https://github.com/LightNetDev/LightNet/pull/356) [`81e5749`](https://github.com/LightNetDev/LightNet/commit/81e57498caa24c480bab43b1f368c9028637dad6) Thanks [@smn-cds](https://github.com/smn-cds)! - **Remove code for experimental Admin UI.**
|
|
8
|
+
|
|
9
|
+
We are exploring a different way to implement it. Yet we consider reusing this code later.
|
|
10
|
+
|
|
11
|
+
- [#358](https://github.com/LightNetDev/LightNet/pull/358) [`ca9f983`](https://github.com/LightNetDev/LightNet/commit/ca9f98337e35878761d353916b189ce7364ddbf2) Thanks [@smn-cds](https://github.com/smn-cds)! - Update dependencies, disable i18next support notice
|
|
12
|
+
|
|
13
|
+
- [#356](https://github.com/LightNetDev/LightNet/pull/356) [`81e5749`](https://github.com/LightNetDev/LightNet/commit/81e57498caa24c480bab43b1f368c9028637dad6) Thanks [@smn-cds](https://github.com/smn-cds)! - Remove unused internal `getRawMediaItems` function.
|
|
14
|
+
|
|
15
|
+
- [#354](https://github.com/LightNetDev/LightNet/pull/354) [`1c3c7ea`](https://github.com/LightNetDev/LightNet/commit/1c3c7eac0384f9c57da89c2abddabd91c20dcfa2) Thanks [@smn-cds](https://github.com/smn-cds)! - Fix search input background on IOS safari
|
|
16
|
+
|
|
17
|
+
- [#354](https://github.com/LightNetDev/LightNet/pull/354) [`1c3c7ea`](https://github.com/LightNetDev/LightNet/commit/1c3c7eac0384f9c57da89c2abddabd91c20dcfa2) Thanks [@smn-cds](https://github.com/smn-cds)! - Do not apply TailwindCSS base styles to every page by default.
|
|
18
|
+
|
|
3
19
|
## 3.12.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/__e2e__/admin.spec.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { expect, type Page } from "@playwright/test"
|
|
1
|
+
import { expect } from "@playwright/test"
|
|
4
2
|
|
|
5
3
|
import { test } from "./basics-fixture"
|
|
6
4
|
|
|
7
|
-
const faithfulFreestyleMediaUrl = new URL(
|
|
8
|
-
"./fixtures/basics/src/content/media/faithful-freestyle--en.json",
|
|
9
|
-
import.meta.url,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
5
|
test.describe("Edit button on details page", () => {
|
|
13
6
|
test("Should not show `Edit` button on details page by default.", async ({
|
|
14
7
|
page,
|
|
@@ -24,361 +17,4 @@ test.describe("Edit button on details page", () => {
|
|
|
24
17
|
const editButton = page.locator("#edit-btn")
|
|
25
18
|
await expect(editButton).toBeHidden()
|
|
26
19
|
})
|
|
27
|
-
|
|
28
|
-
test("Should show `Edit` button on book details page after visiting `/admin/` path.", async ({
|
|
29
|
-
page,
|
|
30
|
-
lightnet,
|
|
31
|
-
}) => {
|
|
32
|
-
const ln = await lightnet()
|
|
33
|
-
|
|
34
|
-
await page.goto(ln.resolveURL("/admin/"))
|
|
35
|
-
await expect(
|
|
36
|
-
page.getByText("Admin features are enabled now.", { exact: true }),
|
|
37
|
-
).toBeVisible()
|
|
38
|
-
|
|
39
|
-
await page.goto(ln.resolveURL("/en/media/faithful-freestyle--en"))
|
|
40
|
-
await expect(
|
|
41
|
-
page.getByRole("heading", { name: "Faithful Freestyle" }),
|
|
42
|
-
).toBeVisible()
|
|
43
|
-
|
|
44
|
-
const editButton = page.locator("#edit-btn")
|
|
45
|
-
await expect(editButton).toBeVisible()
|
|
46
|
-
await expect(editButton).toHaveAttribute(
|
|
47
|
-
"href",
|
|
48
|
-
"/admin/media/faithful-freestyle--en",
|
|
49
|
-
)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test("Should show `Edit` button on video details page after visiting `/admin/` path.", async ({
|
|
53
|
-
page,
|
|
54
|
-
lightnet,
|
|
55
|
-
}) => {
|
|
56
|
-
const ln = await lightnet("/admin/")
|
|
57
|
-
|
|
58
|
-
await expect(
|
|
59
|
-
page.getByText("Admin features are enabled now.", { exact: true }),
|
|
60
|
-
).toBeVisible()
|
|
61
|
-
|
|
62
|
-
await page.goto(ln.resolveURL("/en/media/how-to-kickflip--de"))
|
|
63
|
-
await expect(
|
|
64
|
-
page.getByRole("heading", { name: "Kickflip Anleitung" }),
|
|
65
|
-
).toBeVisible()
|
|
66
|
-
|
|
67
|
-
const editButton = page.locator("#edit-btn")
|
|
68
|
-
await expect(editButton).toBeVisible()
|
|
69
|
-
await expect(editButton).toHaveAttribute(
|
|
70
|
-
"href",
|
|
71
|
-
"/admin/media/how-to-kickflip--de",
|
|
72
|
-
)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test("Should show `Edit` button on audio details page after visiting `/admin/` path.", async ({
|
|
76
|
-
page,
|
|
77
|
-
lightnet,
|
|
78
|
-
}) => {
|
|
79
|
-
const ln = await lightnet("/admin/")
|
|
80
|
-
|
|
81
|
-
await expect(
|
|
82
|
-
page.getByText("Admin features are enabled now.", { exact: true }),
|
|
83
|
-
).toBeVisible()
|
|
84
|
-
|
|
85
|
-
await page.goto(ln.resolveURL("/en/media/skate-sounds--en"))
|
|
86
|
-
await expect(
|
|
87
|
-
page.getByRole("heading", { name: "Skate Sounds" }),
|
|
88
|
-
).toBeVisible()
|
|
89
|
-
|
|
90
|
-
const editButton = page.locator("#edit-btn")
|
|
91
|
-
await expect(editButton).toBeVisible()
|
|
92
|
-
await expect(editButton).toHaveAttribute(
|
|
93
|
-
"href",
|
|
94
|
-
"/admin/media/skate-sounds--en",
|
|
95
|
-
)
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
test("Edit button on details page should navigate to media item edit page", async ({
|
|
99
|
-
page,
|
|
100
|
-
lightnet,
|
|
101
|
-
}) => {
|
|
102
|
-
const ln = await lightnet("/admin/")
|
|
103
|
-
await ln.goto("/en/media/faithful-freestyle--en")
|
|
104
|
-
|
|
105
|
-
const editButton = page.locator("#edit-btn")
|
|
106
|
-
await expect(editButton).toBeVisible()
|
|
107
|
-
|
|
108
|
-
await editButton.click()
|
|
109
|
-
await expect(page).toHaveURL(
|
|
110
|
-
ln.resolveURL("/admin/media/faithful-freestyle--en"),
|
|
111
|
-
)
|
|
112
|
-
await expect(
|
|
113
|
-
page.getByText("Edit media item", { exact: false }),
|
|
114
|
-
).toBeVisible()
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
test.describe("Media item edit page", () => {
|
|
119
|
-
const recordWriteFile = async (page: Page) => {
|
|
120
|
-
type WriteFileRequest = { url: string; body: unknown }
|
|
121
|
-
let resolveWriteFileRequest: ((value: WriteFileRequest) => void) | null =
|
|
122
|
-
null
|
|
123
|
-
const writeFileRequestPromise = new Promise<WriteFileRequest>((resolve) => {
|
|
124
|
-
resolveWriteFileRequest = resolve
|
|
125
|
-
})
|
|
126
|
-
await page.route("**/api/internal/fs/write-file?*", async (route) => {
|
|
127
|
-
const request = route.request()
|
|
128
|
-
resolveWriteFileRequest?.({
|
|
129
|
-
url: request.url(),
|
|
130
|
-
body: JSON.parse(request.postData() ?? ""),
|
|
131
|
-
})
|
|
132
|
-
await route.fulfill({
|
|
133
|
-
status: 200,
|
|
134
|
-
contentType: "application/json",
|
|
135
|
-
body: JSON.stringify({ status: "ok" }),
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
return () => writeFileRequestPromise
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const getPublishButton = (page: Page) =>
|
|
142
|
-
page.getByRole("button", { name: "Publish changes" }).first()
|
|
143
|
-
|
|
144
|
-
const expectPublishedMessage = (page: Page) =>
|
|
145
|
-
expect(
|
|
146
|
-
page.getByRole("button", { name: "Published" }).first(),
|
|
147
|
-
).toBeVisible()
|
|
148
|
-
|
|
149
|
-
test("should edit title", async ({ page, lightnet }) => {
|
|
150
|
-
await lightnet("/admin/media/faithful-freestyle--en")
|
|
151
|
-
const writeFileRequest = await recordWriteFile(page)
|
|
152
|
-
|
|
153
|
-
const updatedTitle = "Faithful Freestyle (Edited)"
|
|
154
|
-
const titleInput = page.getByLabel("Title")
|
|
155
|
-
await expect(titleInput).toHaveValue("Faithful Freestyle")
|
|
156
|
-
await titleInput.fill(updatedTitle)
|
|
157
|
-
|
|
158
|
-
const saveButton = getPublishButton(page)
|
|
159
|
-
await expect(saveButton).toBeEnabled()
|
|
160
|
-
await saveButton.click()
|
|
161
|
-
|
|
162
|
-
const { url, body } = await writeFileRequest()
|
|
163
|
-
expect(url).toContain(
|
|
164
|
-
"/api/internal/fs/write-file?path=src%2Fcontent%2Fmedia%2Ffaithful-freestyle--en.json",
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
const expectedMediaItem = JSON.parse(
|
|
168
|
-
await readFile(faithfulFreestyleMediaUrl, "utf-8"),
|
|
169
|
-
)
|
|
170
|
-
expect(body).toEqual({
|
|
171
|
-
...expectedMediaItem,
|
|
172
|
-
title: updatedTitle,
|
|
173
|
-
})
|
|
174
|
-
await expectPublishedMessage(page)
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
test("Should update media type", async ({ page, lightnet }) => {
|
|
178
|
-
await lightnet("/admin/media/faithful-freestyle--en")
|
|
179
|
-
const writeFileRequest = await recordWriteFile(page)
|
|
180
|
-
|
|
181
|
-
const typeSelect = page.getByLabel("Type").first()
|
|
182
|
-
await expect(typeSelect).toHaveValue("book")
|
|
183
|
-
await typeSelect.selectOption("video")
|
|
184
|
-
|
|
185
|
-
const saveButton = getPublishButton(page)
|
|
186
|
-
await expect(saveButton).toBeEnabled()
|
|
187
|
-
await saveButton.click()
|
|
188
|
-
|
|
189
|
-
const { body } = await writeFileRequest()
|
|
190
|
-
const expectedMediaItem = JSON.parse(
|
|
191
|
-
await readFile(faithfulFreestyleMediaUrl, "utf-8"),
|
|
192
|
-
)
|
|
193
|
-
expect(body).toEqual({
|
|
194
|
-
...expectedMediaItem,
|
|
195
|
-
type: "video",
|
|
196
|
-
})
|
|
197
|
-
await expectPublishedMessage(page)
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
test("Should update author name", async ({ page, lightnet }) => {
|
|
201
|
-
await lightnet("/admin/media/faithful-freestyle--en")
|
|
202
|
-
const writeFileRequest = await recordWriteFile(page)
|
|
203
|
-
|
|
204
|
-
const authorsFieldset = page.getByRole("group", { name: "Authors" })
|
|
205
|
-
const firstAuthorInput = authorsFieldset.getByRole("textbox").first()
|
|
206
|
-
const updatedAuthor = "Sk8 Ministries International"
|
|
207
|
-
await expect(firstAuthorInput).toHaveValue("Sk8 Ministries")
|
|
208
|
-
await firstAuthorInput.fill(updatedAuthor)
|
|
209
|
-
|
|
210
|
-
const saveButton = getPublishButton(page)
|
|
211
|
-
await expect(saveButton).toBeEnabled()
|
|
212
|
-
await saveButton.click()
|
|
213
|
-
|
|
214
|
-
const { body } = await writeFileRequest()
|
|
215
|
-
const expectedMediaItem = JSON.parse(
|
|
216
|
-
await readFile(faithfulFreestyleMediaUrl, "utf-8"),
|
|
217
|
-
)
|
|
218
|
-
expect(body).toEqual({
|
|
219
|
-
...expectedMediaItem,
|
|
220
|
-
authors: [updatedAuthor],
|
|
221
|
-
})
|
|
222
|
-
await expectPublishedMessage(page)
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
test("Should add author", async ({ page, lightnet }) => {
|
|
226
|
-
await lightnet("/admin/media/faithful-freestyle--en")
|
|
227
|
-
const writeFileRequest = await recordWriteFile(page)
|
|
228
|
-
|
|
229
|
-
const authorsFieldset = page.getByRole("group", { name: "Authors" })
|
|
230
|
-
const addAuthorButton = page.getByRole("button", { name: "Add Author" })
|
|
231
|
-
await addAuthorButton.click()
|
|
232
|
-
const newAuthorInput = authorsFieldset.getByRole("textbox").last()
|
|
233
|
-
const additionalAuthor = "Tony Hawk"
|
|
234
|
-
await newAuthorInput.fill(additionalAuthor)
|
|
235
|
-
|
|
236
|
-
const saveButton = getPublishButton(page)
|
|
237
|
-
await expect(saveButton).toBeEnabled()
|
|
238
|
-
await saveButton.click()
|
|
239
|
-
|
|
240
|
-
const { body } = await writeFileRequest()
|
|
241
|
-
const expectedMediaItem = JSON.parse(
|
|
242
|
-
await readFile(faithfulFreestyleMediaUrl, "utf-8"),
|
|
243
|
-
)
|
|
244
|
-
expect(body).toEqual({
|
|
245
|
-
...expectedMediaItem,
|
|
246
|
-
authors: ["Sk8 Ministries", additionalAuthor],
|
|
247
|
-
})
|
|
248
|
-
await expectPublishedMessage(page)
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
test("Should remove author", async ({ page, lightnet }) => {
|
|
252
|
-
await lightnet("/admin/media/faithful-freestyle--en")
|
|
253
|
-
const writeFileRequest = await recordWriteFile(page)
|
|
254
|
-
|
|
255
|
-
const authorsFieldset = page.getByRole("group", { name: "Authors" })
|
|
256
|
-
const addAuthorButton = page.getByRole("button", { name: "Add Author" })
|
|
257
|
-
const replacementAuthor = "Skate Evangelists"
|
|
258
|
-
await addAuthorButton.click()
|
|
259
|
-
const addedAuthorInput = authorsFieldset.getByRole("textbox").last()
|
|
260
|
-
await addedAuthorInput.fill(replacementAuthor)
|
|
261
|
-
|
|
262
|
-
const removeButtons = authorsFieldset.getByRole("button", {
|
|
263
|
-
name: "Remove",
|
|
264
|
-
})
|
|
265
|
-
await removeButtons.first().click()
|
|
266
|
-
|
|
267
|
-
const saveButton = getPublishButton(page)
|
|
268
|
-
await expect(saveButton).toBeEnabled()
|
|
269
|
-
await saveButton.click()
|
|
270
|
-
|
|
271
|
-
const { body } = await writeFileRequest()
|
|
272
|
-
const expectedMediaItem = JSON.parse(
|
|
273
|
-
await readFile(faithfulFreestyleMediaUrl, "utf-8"),
|
|
274
|
-
)
|
|
275
|
-
expect(body).toEqual({
|
|
276
|
-
...expectedMediaItem,
|
|
277
|
-
authors: [replacementAuthor],
|
|
278
|
-
})
|
|
279
|
-
await expectPublishedMessage(page)
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
test("should show error message if common id is set empty", async ({
|
|
283
|
-
page,
|
|
284
|
-
lightnet,
|
|
285
|
-
}) => {
|
|
286
|
-
await lightnet("/admin/media/faithful-freestyle--en")
|
|
287
|
-
|
|
288
|
-
const commonIdInput = page.getByLabel("Common ID")
|
|
289
|
-
await expect(commonIdInput).toHaveValue("faithful-freestyle")
|
|
290
|
-
|
|
291
|
-
await commonIdInput.fill("")
|
|
292
|
-
await commonIdInput.blur()
|
|
293
|
-
|
|
294
|
-
await expect(
|
|
295
|
-
page
|
|
296
|
-
.getByRole("alert")
|
|
297
|
-
.filter({ hasText: "Please enter at least one character." }),
|
|
298
|
-
).toBeVisible()
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
test("should focus invalid field when submitting invalid form data", async ({
|
|
302
|
-
page,
|
|
303
|
-
lightnet,
|
|
304
|
-
}) => {
|
|
305
|
-
await lightnet("/admin/media/faithful-freestyle--en")
|
|
306
|
-
|
|
307
|
-
const categoriesFieldset = page.getByRole("group", { name: "Categories" })
|
|
308
|
-
await page.getByRole("button", { name: "Add Category" }).click()
|
|
309
|
-
const newCategorySelect = categoriesFieldset.getByRole("combobox").last()
|
|
310
|
-
await expect(newCategorySelect).toHaveValue("")
|
|
311
|
-
|
|
312
|
-
// move focus away so the submission handler needs to return focus
|
|
313
|
-
await page.getByLabel("Title").click()
|
|
314
|
-
|
|
315
|
-
const saveButton = getPublishButton(page)
|
|
316
|
-
await saveButton.click()
|
|
317
|
-
|
|
318
|
-
await expect(
|
|
319
|
-
page.getByRole("alert").filter({ hasText: "This field is required." }),
|
|
320
|
-
).toBeVisible()
|
|
321
|
-
await expect(newCategorySelect).toBeFocused()
|
|
322
|
-
})
|
|
323
|
-
|
|
324
|
-
test("should not allow assigning duplicate categories", async ({
|
|
325
|
-
page,
|
|
326
|
-
lightnet,
|
|
327
|
-
}) => {
|
|
328
|
-
await lightnet("/admin/media/faithful-freestyle--en")
|
|
329
|
-
|
|
330
|
-
const categoriesFieldset = page.getByRole("group", { name: "Categories" })
|
|
331
|
-
await page.getByRole("button", { name: "Add Category" }).click()
|
|
332
|
-
|
|
333
|
-
const categorySelects = categoriesFieldset.getByRole("combobox")
|
|
334
|
-
const firstCategoryValue = await categorySelects.first().inputValue()
|
|
335
|
-
const duplicateCategorySelect = categorySelects.last()
|
|
336
|
-
await duplicateCategorySelect.selectOption(firstCategoryValue)
|
|
337
|
-
|
|
338
|
-
const publishButton = getPublishButton(page)
|
|
339
|
-
await publishButton.click()
|
|
340
|
-
|
|
341
|
-
const duplicateCategoryError = categoriesFieldset
|
|
342
|
-
.getByRole("alert")
|
|
343
|
-
.filter({ hasText: "Please choose a different value for each entry." })
|
|
344
|
-
await expect(duplicateCategoryError).toBeVisible()
|
|
345
|
-
await expect(duplicateCategorySelect).toHaveAttribute(
|
|
346
|
-
"aria-invalid",
|
|
347
|
-
"true",
|
|
348
|
-
)
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
test("should not submit the form on enter", async ({ page, lightnet }) => {
|
|
352
|
-
await lightnet("/admin/media/faithful-freestyle--en")
|
|
353
|
-
const writeFileRequest = await recordWriteFile(page)
|
|
354
|
-
const writePromise = writeFileRequest()
|
|
355
|
-
|
|
356
|
-
const updatedTitle = "Faithful Freestyle (Enter key)"
|
|
357
|
-
const titleInput = page.getByLabel("Title")
|
|
358
|
-
await titleInput.fill(updatedTitle)
|
|
359
|
-
|
|
360
|
-
const publishButton = getPublishButton(page)
|
|
361
|
-
await expect(publishButton).toBeEnabled()
|
|
362
|
-
|
|
363
|
-
await titleInput.press("Enter")
|
|
364
|
-
|
|
365
|
-
const enterResult = await Promise.race([
|
|
366
|
-
writePromise.then(() => "submitted"),
|
|
367
|
-
page.waitForTimeout(500).then(() => "timeout"),
|
|
368
|
-
])
|
|
369
|
-
expect(enterResult).toBe("timeout")
|
|
370
|
-
await expect(publishButton).toBeEnabled()
|
|
371
|
-
|
|
372
|
-
await publishButton.click()
|
|
373
|
-
|
|
374
|
-
const expectedMediaItem = JSON.parse(
|
|
375
|
-
await readFile(faithfulFreestyleMediaUrl, "utf-8"),
|
|
376
|
-
)
|
|
377
|
-
const { body } = await writePromise
|
|
378
|
-
expect(body).toEqual({
|
|
379
|
-
...expectedMediaItem,
|
|
380
|
-
title: updatedTitle,
|
|
381
|
-
})
|
|
382
|
-
await expectPublishedMessage(page)
|
|
383
|
-
})
|
|
384
20
|
})
|
|
@@ -10,9 +10,9 @@ case `uname` in
|
|
|
10
10
|
esac
|
|
11
11
|
|
|
12
12
|
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.
|
|
13
|
+
export NODE_PATH="/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.17.2_@types+node@25.0.3_jiti@2.4.2_lightningcss@1.29.1_rollup@4.57.1_terser@5.39.0_typescript@5.9.3_yaml@2.8.2/node_modules/astro/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.17.2_@types+node@25.0.3_jiti@2.4.2_lightningcss@1.29.1_rollup@4.57.1_terser@5.39.0_typescript@5.9.3_yaml@2.8.2/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/node_modules"
|
|
14
14
|
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.
|
|
15
|
+
export NODE_PATH="/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.17.2_@types+node@25.0.3_jiti@2.4.2_lightningcss@1.29.1_rollup@4.57.1_terser@5.39.0_typescript@5.9.3_yaml@2.8.2/node_modules/astro/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.17.2_@types+node@25.0.3_jiti@2.4.2_lightningcss@1.29.1_rollup@4.57.1_terser@5.39.0_typescript@5.9.3_yaml@2.8.2/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
16
|
fi
|
|
17
17
|
if [ -x "$basedir/node" ]; then
|
|
18
18
|
exec "$basedir/node" "$basedir/../astro/astro.js" "$@"
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
"@astrojs/react": "^4.4.2",
|
|
8
8
|
"@astrojs/tailwind": "^6.0.2",
|
|
9
9
|
"@lightnet/decap-admin": "^3.1.4",
|
|
10
|
-
"astro": "^5.
|
|
10
|
+
"astro": "^5.17.2",
|
|
11
11
|
"lightnet": "^3.12.0",
|
|
12
|
-
"react": "^19.2.
|
|
13
|
-
"react-dom": "^19.2.
|
|
12
|
+
"react": "^19.2.4",
|
|
13
|
+
"react-dom": "^19.2.4",
|
|
14
14
|
"sharp": "^0.34.5",
|
|
15
15
|
"tailwindcss": "^3.4.19",
|
|
16
16
|
"typescript": "^5.9.3"
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "LightNet makes it easy to run your own digital media library.",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "3.12.
|
|
6
|
+
"version": "3.12.1",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/LightNetDev/lightnet",
|
|
@@ -32,11 +32,7 @@
|
|
|
32
32
|
"./pages/SearchPageRoute.astro": "./src/pages/search-page/SearchPageRoute.astro",
|
|
33
33
|
"./pages/DetailsPageRoute.astro": "./src/pages/details-page/DetailsPageRoute.astro",
|
|
34
34
|
"./api/internal/search.ts": "./src/pages/search-page/api/search.ts",
|
|
35
|
-
"./api/versions.ts": "./src/api/versions.ts"
|
|
36
|
-
"./api/media/[mediaId].ts": "./src/api/media/[mediaId].ts",
|
|
37
|
-
"./api/internal/fs/write-file.ts": "./src/admin/api/fs/write-file.ts",
|
|
38
|
-
"./admin/pages/AdminRoute.astro": "./src/admin/pages/AdminRoute.astro",
|
|
39
|
-
"./admin/pages/media/EditRoute.astro": "./src/admin/pages/media/EditRoute.astro"
|
|
35
|
+
"./api/versions.ts": "./src/api/versions.ts"
|
|
40
36
|
},
|
|
41
37
|
"peerDependencies": {
|
|
42
38
|
"astro": "^5.1.0",
|
|
@@ -47,27 +43,24 @@
|
|
|
47
43
|
"dependencies": {
|
|
48
44
|
"@astrojs/react": "^4.4.2",
|
|
49
45
|
"@astrojs/tailwind": "^6.0.2",
|
|
50
|
-
"@hookform/resolvers": "^5.2.2",
|
|
51
46
|
"@iconify-json/mdi": "^1.2.3",
|
|
52
47
|
"@iconify/tailwind": "^1.2.0",
|
|
53
|
-
"@mdxeditor/editor": "^3.52.3",
|
|
54
48
|
"@tailwindcss/typography": "^0.5.19",
|
|
55
|
-
"@tanstack/react-virtual": "^3.13.
|
|
49
|
+
"@tanstack/react-virtual": "^3.13.18",
|
|
56
50
|
"daisyui": "^4.12.24",
|
|
57
51
|
"embla-carousel": "^8.6.0",
|
|
58
52
|
"embla-carousel-wheel-gestures": "^8.1.0",
|
|
59
53
|
"fuse.js": "^7.1.0",
|
|
60
|
-
"i18next": "^25.
|
|
54
|
+
"i18next": "^25.8.5",
|
|
61
55
|
"marked": "^16.4.2",
|
|
62
|
-
"react-hook-form": "^7.70.0",
|
|
63
56
|
"yaml": "^2.8.2"
|
|
64
57
|
},
|
|
65
58
|
"devDependencies": {
|
|
66
|
-
"@playwright/test": "^1.
|
|
67
|
-
"@types/node": "^22.19.
|
|
68
|
-
"@types/react": "^19.2.
|
|
59
|
+
"@playwright/test": "^1.58.2",
|
|
60
|
+
"@types/node": "^22.19.11",
|
|
61
|
+
"@types/react": "^19.2.14",
|
|
69
62
|
"typescript": "^5.9.3",
|
|
70
|
-
"vitest": "^4.0.
|
|
63
|
+
"vitest": "^4.0.18"
|
|
71
64
|
},
|
|
72
65
|
"engines": {
|
|
73
66
|
"node": ">=22"
|
|
@@ -220,28 +220,7 @@ export const configSchema = z.object({
|
|
|
220
220
|
/**
|
|
221
221
|
* Experimental features. Subject to change with any release.
|
|
222
222
|
*/
|
|
223
|
-
experimental: z
|
|
224
|
-
.object({
|
|
225
|
-
/**
|
|
226
|
-
* Configure administration interface.
|
|
227
|
-
*/
|
|
228
|
-
admin: z
|
|
229
|
-
.object({
|
|
230
|
-
enabled: z.boolean().default(false),
|
|
231
|
-
/**
|
|
232
|
-
* Currently we only support english as Admin UI language.
|
|
233
|
-
*/
|
|
234
|
-
languageCode: z.literal("en").default("en"),
|
|
235
|
-
/**
|
|
236
|
-
* Max file size to upload in mega bytes.
|
|
237
|
-
*
|
|
238
|
-
* Default is 25 (this aligns with Cloudflare's max file size).
|
|
239
|
-
*/
|
|
240
|
-
maxFileSize: z.number().default(25),
|
|
241
|
-
})
|
|
242
|
-
.optional(),
|
|
243
|
-
})
|
|
244
|
-
.optional(),
|
|
223
|
+
experimental: z.object({}).optional(),
|
|
245
224
|
})
|
|
246
225
|
|
|
247
226
|
export type Language = z.input<typeof languageSchema>
|
|
@@ -19,7 +19,6 @@ export function lightnet(lightnetConfig: LightnetConfig): AstroIntegration {
|
|
|
19
19
|
updateConfig,
|
|
20
20
|
logger,
|
|
21
21
|
addMiddleware,
|
|
22
|
-
command,
|
|
23
22
|
}) => {
|
|
24
23
|
const config = verifySchema(
|
|
25
24
|
configSchema,
|
|
@@ -64,46 +63,12 @@ export function lightnet(lightnetConfig: LightnetConfig): AstroIntegration {
|
|
|
64
63
|
prerender: true,
|
|
65
64
|
})
|
|
66
65
|
|
|
67
|
-
if (config.experimental?.admin?.enabled) {
|
|
68
|
-
injectRoute({
|
|
69
|
-
pattern: "/api/media/[mediaId].json",
|
|
70
|
-
entrypoint: "lightnet/api/media/[mediaId].ts",
|
|
71
|
-
prerender: true,
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
injectRoute({
|
|
75
|
-
pattern: "/admin",
|
|
76
|
-
entrypoint: "lightnet/admin/pages/AdminRoute.astro",
|
|
77
|
-
prerender: true,
|
|
78
|
-
})
|
|
79
|
-
injectRoute({
|
|
80
|
-
pattern: "/admin/media/[mediaId]",
|
|
81
|
-
entrypoint: "lightnet/admin/pages/media/EditRoute.astro",
|
|
82
|
-
prerender: true,
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// During local development admin ui can use
|
|
87
|
-
// this endpoints to write files.
|
|
88
|
-
if (config.experimental?.admin?.enabled && command === "dev") {
|
|
89
|
-
injectRoute({
|
|
90
|
-
pattern: "/api/internal/fs/write-file",
|
|
91
|
-
entrypoint: "lightnet/api/internal/fs/write-file.ts",
|
|
92
|
-
prerender: false,
|
|
93
|
-
})
|
|
94
|
-
// Add empty adapter to avoid warning
|
|
95
|
-
// about missing adapter.
|
|
96
|
-
// This hack might break in the future :(
|
|
97
|
-
// We could also set the "node" adapter if no
|
|
98
|
-
// adapter has been set by user.
|
|
99
|
-
if (!astroConfig.adapter) {
|
|
100
|
-
updateConfig({ adapter: {} })
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
66
|
addMiddleware({ entrypoint: "lightnet/locals", order: "pre" })
|
|
105
67
|
|
|
106
|
-
astroConfig.integrations.push(
|
|
68
|
+
astroConfig.integrations.push(
|
|
69
|
+
tailwind({ applyBaseStyles: false }),
|
|
70
|
+
react(),
|
|
71
|
+
)
|
|
107
72
|
|
|
108
73
|
updateConfig({
|
|
109
74
|
vite: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getCollection, getEntry } from "astro:content"
|
|
2
2
|
|
|
3
3
|
import { verifySchemaAsync } from "../utils/verify-schema"
|
|
4
|
-
import {
|
|
4
|
+
import { mediaItemEntrySchema } from "./content-schema"
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Internal API to get media items. Since this package is a Astro integration
|
|
@@ -26,49 +26,3 @@ const prepareItem = async (item: unknown) => {
|
|
|
26
26
|
(id) => `Fix these issues inside "src/content/media/${id}.json":`,
|
|
27
27
|
)
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Revert media items like they it is stored in the
|
|
32
|
-
* content collection folder.
|
|
33
|
-
*/
|
|
34
|
-
export const getRawMediaItem = async (id: string) => {
|
|
35
|
-
const item = await getMediaItem(id)
|
|
36
|
-
return revertMediaItemEntry(item)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Revert media items like they are stored in the
|
|
41
|
-
* content collection folder.
|
|
42
|
-
*/
|
|
43
|
-
export const getRawMediaItems = async () => {
|
|
44
|
-
const mediaItems = await getMediaItems()
|
|
45
|
-
return Promise.all(mediaItems.map(revertMediaItemEntry))
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Returns the media item like it is stored in the content collection json.
|
|
50
|
-
* We need to revert Astro's modifications to references and images.
|
|
51
|
-
*
|
|
52
|
-
* @param mediaItem media item parsed by Astro
|
|
53
|
-
* @returns media item like before parsing
|
|
54
|
-
*/
|
|
55
|
-
async function revertMediaItemEntry({ id, data: mediaItem }: MediaItemEntry) {
|
|
56
|
-
const type = mediaItem.type.id
|
|
57
|
-
const categories = mediaItem.categories?.map((category) => category.id)
|
|
58
|
-
const collections = mediaItem.collections?.map((collection) => ({
|
|
59
|
-
...collection,
|
|
60
|
-
collection: collection.collection.id,
|
|
61
|
-
}))
|
|
62
|
-
const image =
|
|
63
|
-
(await getEntry("internal-media-image-path", id))?.data.image ?? ""
|
|
64
|
-
return {
|
|
65
|
-
id,
|
|
66
|
-
data: {
|
|
67
|
-
...mediaItem,
|
|
68
|
-
type,
|
|
69
|
-
categories,
|
|
70
|
-
collections,
|
|
71
|
-
image,
|
|
72
|
-
},
|
|
73
|
-
}
|
|
74
|
-
}
|
package/src/i18n/translate.ts
CHANGED