robodev 0.21.0 → 0.22.0
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/package.json +1 -1
- package/src/emit-starter.test.ts +2 -2
- package/src/index.ts +14 -4
- package/src/print-live-url.test.ts +31 -0
- package/src/print-live-url.ts +6 -0
- package/templates/auth-chat/.rulesync/skills/media-feature/SKILL.md +6 -6
- package/templates/auth-chat/package.json +1 -1
- package/templates/backend/api/_lib.ts +40 -15
- package/templates/backend/api/planets/[id].ts +23 -8
- package/templates/backend/api/planets.ts +14 -9
- package/templates/backend/package.json +1 -1
- package/templates/empty/package.json +1 -1
- package/templates/space/.rulesync/skills/media-feature/SKILL.md +6 -6
- package/templates/space/api/_lib.ts +40 -15
- package/templates/space/api/planets/[id].ts +23 -8
- package/templates/space/api/planets.ts +14 -9
- package/templates/space/apps/fe/src/assets/locales/en/translation.json +1 -0
- package/templates/space/apps/fe/src/assets/locales/sl/translation.json +1 -0
- package/templates/space/apps/fe/src/components/features/planets/details/PlanetEditPage.tsx +69 -33
- package/templates/space/apps/fe/src/components/features/planets/list/PlanetCreateModal.tsx +23 -20
- package/templates/space/apps/fe/src/utils/planet-form.test.ts +68 -0
- package/templates/space/apps/fe/src/utils/planet-form.ts +49 -0
- package/templates/space/apps/fe/src/utils/planet-submit.ts +25 -0
- package/templates/space/openapi.json +14 -131
- package/templates/space/package.json +1 -1
- package/templates/backend/api/files/upload-request.ts +0 -48
- package/templates/backend/api/files/upload.ts +0 -29
- package/templates/space/api/files/upload-request.ts +0 -48
- package/templates/space/api/files/upload.ts +0 -29
- package/templates/space/apps/fe/src/utils/media-upload-headers.ts +0 -8
- package/templates/space/apps/fe/src/utils/media-upload.test.ts +0 -19
- package/templates/space/apps/fe/src/utils/media-upload.ts +0 -72
|
@@ -9,9 +9,9 @@ import {
|
|
|
9
9
|
TextInput,
|
|
10
10
|
Typography,
|
|
11
11
|
useForm,
|
|
12
|
-
useFormValue,
|
|
13
12
|
useToast,
|
|
14
13
|
} from "@povio/ui/tanstack";
|
|
14
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
15
15
|
import { useNavigate } from "@tanstack/react-router";
|
|
16
16
|
import { Trash } from "lucide-react";
|
|
17
17
|
import { useEffect, useState } from "react";
|
|
@@ -19,10 +19,10 @@ import { useTranslation } from "react-i18next";
|
|
|
19
19
|
|
|
20
20
|
import { RowInputWrapper } from "@/components/shared/forms/RowInputWrapper";
|
|
21
21
|
import { AlienQueries } from "@/openapi/alien/alien.queries";
|
|
22
|
-
import { MediaModels } from "@/openapi/media/media.models";
|
|
23
22
|
import { PlanetModels } from "@/openapi/planet/planet.models";
|
|
24
23
|
import { PlanetQueries } from "@/openapi/planet/planet.queries";
|
|
25
|
-
import {
|
|
24
|
+
import { bindLocalPlanetImage } from "@/utils/planet-form";
|
|
25
|
+
import { updatePlanet } from "@/utils/planet-submit";
|
|
26
26
|
|
|
27
27
|
interface PlanetEditPageProps {
|
|
28
28
|
planet: PlanetModels.PlanetsGetResponseDto;
|
|
@@ -34,11 +34,14 @@ interface PlanetEditPageProps {
|
|
|
34
34
|
export function PlanetEditPage({ planet, onClose, onDeleted, onSaved }: PlanetEditPageProps) {
|
|
35
35
|
const { t } = useTranslation();
|
|
36
36
|
const navigate = useNavigate();
|
|
37
|
-
const
|
|
37
|
+
const queryClient = useQueryClient();
|
|
38
38
|
const deletePlanet = PlanetQueries.useDeleteApiPlanetsById();
|
|
39
39
|
const { successToast, errorToast } = useToast();
|
|
40
40
|
const { confirm } = Confirmation.useConfirmation();
|
|
41
|
-
const [
|
|
41
|
+
const [pickedFile, setPickedFile] = useState<File | null>(null);
|
|
42
|
+
const [clearedExisting, setClearedExisting] = useState(false);
|
|
43
|
+
const [previewObjectUrl, setPreviewObjectUrl] = useState<string | undefined>();
|
|
44
|
+
const [isPending, setIsPending] = useState(false);
|
|
42
45
|
// Seed the form from the fetched record, then reset when route data changes between planet IDs.
|
|
43
46
|
const form = useForm({
|
|
44
47
|
zodSchema: PlanetModels.PlanetsCreateRequestDtoSchema,
|
|
@@ -47,7 +50,6 @@ export function PlanetEditPage({ planet, onClose, onDeleted, onSaved }: PlanetEd
|
|
|
47
50
|
alienId: planet.alienId ?? undefined,
|
|
48
51
|
discoveryDate: planet.discoveryDate ?? undefined,
|
|
49
52
|
description: planet.description ?? "",
|
|
50
|
-
image: planet.image ? { id: planet.image.id } : undefined,
|
|
51
53
|
},
|
|
52
54
|
});
|
|
53
55
|
|
|
@@ -57,30 +59,46 @@ export function PlanetEditPage({ planet, onClose, onDeleted, onSaved }: PlanetEd
|
|
|
57
59
|
alienId: planet.alienId ?? undefined,
|
|
58
60
|
discoveryDate: planet.discoveryDate ?? undefined,
|
|
59
61
|
description: planet.description ?? "",
|
|
60
|
-
image: planet.image ? { id: planet.image.id } : undefined,
|
|
61
62
|
});
|
|
62
|
-
|
|
63
|
+
setPickedFile(null);
|
|
64
|
+
setClearedExisting(false);
|
|
65
|
+
setPreviewObjectUrl((current) => {
|
|
66
|
+
if (current) URL.revokeObjectURL(current);
|
|
67
|
+
return undefined;
|
|
68
|
+
});
|
|
63
69
|
}, [form, planet]);
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
},
|
|
71
|
-
});
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
return () => {
|
|
73
|
+
if (previewObjectUrl) URL.revokeObjectURL(previewObjectUrl);
|
|
74
|
+
};
|
|
75
|
+
}, [previewObjectUrl]);
|
|
72
76
|
|
|
73
|
-
const handleImageChange = (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
const handleImageChange = (file: File | null) => {
|
|
78
|
+
setPickedFile(file);
|
|
79
|
+
setPreviewObjectUrl((current) => {
|
|
80
|
+
if (current) URL.revokeObjectURL(current);
|
|
81
|
+
return file ? URL.createObjectURL(file) : undefined;
|
|
82
|
+
});
|
|
83
|
+
if (file) {
|
|
84
|
+
setClearedExisting(false);
|
|
78
85
|
}
|
|
79
86
|
};
|
|
80
87
|
|
|
88
|
+
const localImage = bindLocalPlanetImage(handleImageChange);
|
|
89
|
+
|
|
81
90
|
const onSubmit = async (data: PlanetModels.PlanetsCreateRequestDto) => {
|
|
82
91
|
try {
|
|
83
|
-
|
|
92
|
+
setIsPending(true);
|
|
93
|
+
await updatePlanet(planet.id, {
|
|
94
|
+
name: data.name,
|
|
95
|
+
alienId: data.alienId,
|
|
96
|
+
discoveryDate: data.discoveryDate,
|
|
97
|
+
description: data.description,
|
|
98
|
+
file: pickedFile,
|
|
99
|
+
clearImage: Boolean(clearedExisting && !pickedFile && planet.image),
|
|
100
|
+
});
|
|
101
|
+
await queryClient.invalidateQueries({ queryKey: PlanetQueries.keys.all });
|
|
84
102
|
successToast({ text: t(($) => $.planets.edit.success) });
|
|
85
103
|
if (onSaved) {
|
|
86
104
|
onSaved();
|
|
@@ -89,6 +107,8 @@ export function PlanetEditPage({ planet, onClose, onDeleted, onSaved }: PlanetEd
|
|
|
89
107
|
}
|
|
90
108
|
} catch {
|
|
91
109
|
errorToast({ text: t(($) => $.planets.edit.error) });
|
|
110
|
+
} finally {
|
|
111
|
+
setIsPending(false);
|
|
92
112
|
}
|
|
93
113
|
};
|
|
94
114
|
|
|
@@ -121,8 +141,11 @@ export function PlanetEditPage({ planet, onClose, onDeleted, onSaved }: PlanetEd
|
|
|
121
141
|
}
|
|
122
142
|
};
|
|
123
143
|
|
|
124
|
-
const
|
|
125
|
-
|
|
144
|
+
const currentImageUrl = pickedFile
|
|
145
|
+
? previewObjectUrl
|
|
146
|
+
: clearedExisting
|
|
147
|
+
? undefined
|
|
148
|
+
: planet.image?.url;
|
|
126
149
|
const handleClose = () => {
|
|
127
150
|
if (onClose) {
|
|
128
151
|
onClose();
|
|
@@ -222,16 +245,29 @@ export function PlanetEditPage({ planet, onClose, onDeleted, onSaved }: PlanetEd
|
|
|
222
245
|
uploadText={t(($) => $.planets.edit.imageUploadText)}
|
|
223
246
|
browseText={t(($) => $.planets.edit.imageBrowseText)}
|
|
224
247
|
acceptedFileTypes={["image/jpeg", "image/png", "image/webp"]}
|
|
225
|
-
|
|
226
|
-
fileUpload={handleImageUpload}
|
|
248
|
+
{...localImage}
|
|
227
249
|
/>
|
|
228
250
|
{currentImageUrl && (
|
|
229
|
-
<div className="
|
|
230
|
-
<
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
251
|
+
<div className="flex flex-col gap-2">
|
|
252
|
+
<div className="aspect-video w-full overflow-hidden rounded-sm border border-elevation-outline-default-1 bg-elevation-fill-default-2">
|
|
253
|
+
<img
|
|
254
|
+
src={currentImageUrl}
|
|
255
|
+
alt=""
|
|
256
|
+
className="h-full w-full object-cover"
|
|
257
|
+
/>
|
|
258
|
+
</div>
|
|
259
|
+
{!pickedFile && planet.image && !clearedExisting && (
|
|
260
|
+
<Button
|
|
261
|
+
type="button"
|
|
262
|
+
variant="outlined"
|
|
263
|
+
size="xs"
|
|
264
|
+
color="secondary"
|
|
265
|
+
width="hug"
|
|
266
|
+
onPress={() => setClearedExisting(true)}
|
|
267
|
+
>
|
|
268
|
+
{t(($) => $.planets.edit.imageRemove)}
|
|
269
|
+
</Button>
|
|
270
|
+
)}
|
|
235
271
|
</div>
|
|
236
272
|
)}
|
|
237
273
|
</div>
|
|
@@ -254,8 +290,8 @@ export function PlanetEditPage({ planet, onClose, onDeleted, onSaved }: PlanetEd
|
|
|
254
290
|
size="xs"
|
|
255
291
|
color="primary"
|
|
256
292
|
width="hug"
|
|
257
|
-
isDisabled={
|
|
258
|
-
isLoading={
|
|
293
|
+
isDisabled={isPending}
|
|
294
|
+
isLoading={isPending}
|
|
259
295
|
>
|
|
260
296
|
{t(($) => $.planets.edit.submit)}
|
|
261
297
|
</Button>
|
|
@@ -10,14 +10,16 @@ import {
|
|
|
10
10
|
useForm,
|
|
11
11
|
useToast,
|
|
12
12
|
} from "@povio/ui/tanstack";
|
|
13
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
14
|
+
import { useState } from "react";
|
|
13
15
|
import { useTranslation } from "react-i18next";
|
|
14
16
|
|
|
15
17
|
import { RowInputWrapper } from "@/components/shared/forms/RowInputWrapper";
|
|
16
18
|
import { AlienQueries } from "@/openapi/alien/alien.queries";
|
|
17
|
-
import { MediaModels } from "@/openapi/media/media.models";
|
|
18
19
|
import { PlanetModels } from "@/openapi/planet/planet.models";
|
|
19
20
|
import { PlanetQueries } from "@/openapi/planet/planet.queries";
|
|
20
|
-
import {
|
|
21
|
+
import { bindLocalPlanetImage } from "@/utils/planet-form";
|
|
22
|
+
import { createPlanet } from "@/utils/planet-submit";
|
|
21
23
|
|
|
22
24
|
interface PlanetCreateModalProps {
|
|
23
25
|
isOpen: boolean;
|
|
@@ -28,8 +30,10 @@ const useAlienLabelsQuery = AlienQueries.useGetLabels as never;
|
|
|
28
30
|
|
|
29
31
|
export function PlanetCreateModal({ isOpen, onClose }: PlanetCreateModalProps) {
|
|
30
32
|
const { t } = useTranslation();
|
|
31
|
-
const
|
|
33
|
+
const queryClient = useQueryClient();
|
|
32
34
|
const { successToast, errorToast } = useToast();
|
|
35
|
+
const [pickedFile, setPickedFile] = useState<File | null>(null);
|
|
36
|
+
const [isPending, setIsPending] = useState(false);
|
|
33
37
|
// Generated schemas drive form typing and validation; do not import backend types in frontend code.
|
|
34
38
|
const form = useForm({
|
|
35
39
|
zodSchema: PlanetModels.PlanetsCreateRequestDtoSchema,
|
|
@@ -38,34 +42,34 @@ export function PlanetCreateModal({ isOpen, onClose }: PlanetCreateModalProps) {
|
|
|
38
42
|
alienId: undefined,
|
|
39
43
|
discoveryDate: undefined,
|
|
40
44
|
description: "",
|
|
41
|
-
image: undefined,
|
|
42
45
|
},
|
|
43
46
|
});
|
|
44
47
|
|
|
45
|
-
const handleImageUpload = useMediaUploadHandler({
|
|
46
|
-
resourceName: MediaModels.MediaResourceName["planet-image"],
|
|
47
|
-
onUploaded: (media) => form.setFieldValue("image", { id: media.id }),
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const handleImageChange = (file: File | null) => {
|
|
51
|
-
if (!file) {
|
|
52
|
-
form.setFieldValue("image", undefined);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
48
|
const onSubmit = async (data: PlanetModels.PlanetsCreateRequestDto) => {
|
|
57
49
|
try {
|
|
58
|
-
|
|
50
|
+
setIsPending(true);
|
|
51
|
+
await createPlanet({
|
|
52
|
+
name: data.name,
|
|
53
|
+
alienId: data.alienId,
|
|
54
|
+
discoveryDate: data.discoveryDate,
|
|
55
|
+
description: data.description,
|
|
56
|
+
file: pickedFile,
|
|
57
|
+
});
|
|
58
|
+
await queryClient.invalidateQueries({ queryKey: PlanetQueries.keys.all });
|
|
59
59
|
successToast({ text: t(($) => $.planets.create.success) });
|
|
60
60
|
form.reset();
|
|
61
|
+
setPickedFile(null);
|
|
61
62
|
onClose();
|
|
62
63
|
} catch {
|
|
63
64
|
errorToast({ text: t(($) => $.planets.create.error) });
|
|
65
|
+
} finally {
|
|
66
|
+
setIsPending(false);
|
|
64
67
|
}
|
|
65
68
|
};
|
|
66
69
|
|
|
67
70
|
const handleClose = () => {
|
|
68
71
|
form.reset();
|
|
72
|
+
setPickedFile(null);
|
|
69
73
|
onClose();
|
|
70
74
|
};
|
|
71
75
|
|
|
@@ -145,8 +149,7 @@ export function PlanetCreateModal({ isOpen, onClose }: PlanetCreateModalProps) {
|
|
|
145
149
|
uploadText={t(($) => $.planets.create.imageUploadText)}
|
|
146
150
|
browseText={t(($) => $.planets.create.imageBrowseText)}
|
|
147
151
|
acceptedFileTypes={["image/jpeg", "image/png", "image/webp"]}
|
|
148
|
-
|
|
149
|
-
fileUpload={handleImageUpload}
|
|
152
|
+
{...bindLocalPlanetImage((file) => setPickedFile(file))}
|
|
150
153
|
/>
|
|
151
154
|
|
|
152
155
|
<div className="mt-6 flex items-center justify-end gap-2 self-end">
|
|
@@ -167,8 +170,8 @@ export function PlanetCreateModal({ isOpen, onClose }: PlanetCreateModalProps) {
|
|
|
167
170
|
size="xs"
|
|
168
171
|
color="primary"
|
|
169
172
|
width="hug"
|
|
170
|
-
isDisabled={
|
|
171
|
-
isLoading={
|
|
173
|
+
isDisabled={isPending}
|
|
174
|
+
isLoading={isPending}
|
|
172
175
|
>
|
|
173
176
|
{t(($) => $.planets.create.submit)}
|
|
174
177
|
</Button>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
bindLocalPlanetImage,
|
|
5
|
+
buildPlanetFormData,
|
|
6
|
+
localPlanetImageUpload,
|
|
7
|
+
planetFormRequestConfig,
|
|
8
|
+
} from "./planet-form";
|
|
9
|
+
|
|
10
|
+
describe("planet multipart submit", () => {
|
|
11
|
+
it("builds FormData with text fields and an optional file", () => {
|
|
12
|
+
const file = new File(["png"], "mars.png", { type: "image/png" });
|
|
13
|
+
const form = buildPlanetFormData({
|
|
14
|
+
name: "Mars",
|
|
15
|
+
description: "Cold desert",
|
|
16
|
+
file,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
expect(form.get("name")).toBe("Mars");
|
|
20
|
+
expect(form.get("description")).toBe("Cold desert");
|
|
21
|
+
const uploaded = form.get("file") as File;
|
|
22
|
+
expect(uploaded).toBeInstanceOf(File);
|
|
23
|
+
expect(uploaded.name).toBe("mars.png");
|
|
24
|
+
expect(uploaded.type).toBe("image/png");
|
|
25
|
+
expect(form.get("clearImage")).toBeNull();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("sends clearImage only when the existing image was cleared and no file was picked", () => {
|
|
29
|
+
const form = buildPlanetFormData({
|
|
30
|
+
name: "Mars",
|
|
31
|
+
clearImage: true,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(form.get("clearImage")).toBe("true");
|
|
35
|
+
|
|
36
|
+
const withFile = buildPlanetFormData({
|
|
37
|
+
name: "Mars",
|
|
38
|
+
clearImage: true,
|
|
39
|
+
file: new File(["png"], "mars.png", { type: "image/png" }),
|
|
40
|
+
});
|
|
41
|
+
expect(withFile.get("clearImage")).toBeNull();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("does not set Content-Type so the browser can add the multipart boundary", () => {
|
|
45
|
+
const config = planetFormRequestConfig() as { headers?: Record<string, string> };
|
|
46
|
+
expect(config.headers?.["Content-Type"]).toBeUndefined();
|
|
47
|
+
expect("Content-Type" in (config.headers ?? {})).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("local FileUpload handler never fetches", async () => {
|
|
51
|
+
const file = new File(["png"], "mars.png", { type: "image/png" });
|
|
52
|
+
const result = await localPlanetImageUpload({ data: {} } as never, file);
|
|
53
|
+
expect(result).toEqual({ id: "mars.png" });
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("bindLocalPlanetImage keeps the File locally and clears without fetching", async () => {
|
|
57
|
+
const seen: Array<File | null> = [];
|
|
58
|
+
const handlers = bindLocalPlanetImage((file) => seen.push(file));
|
|
59
|
+
const file = new File(["png"], "mars.png", { type: "image/png" });
|
|
60
|
+
|
|
61
|
+
await handlers.fileUpload({ data: {} }, file);
|
|
62
|
+
await handlers.fileRemove();
|
|
63
|
+
|
|
64
|
+
expect(seen).toHaveLength(2);
|
|
65
|
+
expect(seen[0]).toBe(file);
|
|
66
|
+
expect(seen[1]).toBeNull();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export type PlanetWriteFields = {
|
|
2
|
+
name: string;
|
|
3
|
+
alienId?: string | null;
|
|
4
|
+
discoveryDate?: string | Date | null;
|
|
5
|
+
description?: string | null;
|
|
6
|
+
file?: File | null;
|
|
7
|
+
clearImage?: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function appendOptional(form: FormData, key: string, value: unknown) {
|
|
11
|
+
if (value == null || value === "") return;
|
|
12
|
+
if (value instanceof Date) {
|
|
13
|
+
form.append(key, value.toISOString());
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
form.append(key, String(value));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function buildPlanetFormData(fields: PlanetWriteFields): FormData {
|
|
20
|
+
const form = new FormData();
|
|
21
|
+
form.append("name", fields.name);
|
|
22
|
+
appendOptional(form, "alienId", fields.alienId);
|
|
23
|
+
appendOptional(form, "discoveryDate", fields.discoveryDate);
|
|
24
|
+
appendOptional(form, "description", fields.description);
|
|
25
|
+
if (fields.file) form.append("file", fields.file);
|
|
26
|
+
if (fields.clearImage && !fields.file) form.append("clearImage", "true");
|
|
27
|
+
return form;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Axios/browser must set the multipart boundary. Never set Content-Type. */
|
|
31
|
+
export function planetFormRequestConfig() {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function localPlanetImageUpload(_request: unknown, file: File): Promise<{ id: string }> {
|
|
36
|
+
return { id: file.name };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function bindLocalPlanetImage(onFile: (file: File | null) => void) {
|
|
40
|
+
return {
|
|
41
|
+
fileUpload: async (request: unknown, file: File) => {
|
|
42
|
+
onFile(file);
|
|
43
|
+
return localPlanetImageUpload(request, file);
|
|
44
|
+
},
|
|
45
|
+
fileRemove: async () => {
|
|
46
|
+
onFile(null);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AppRestClient } from "@/clients/app-rest-client";
|
|
2
|
+
import { PlanetModels } from "@/openapi/planet/planet.models";
|
|
3
|
+
|
|
4
|
+
import { buildPlanetFormData, planetFormRequestConfig, type PlanetWriteFields } from "./planet-form";
|
|
5
|
+
|
|
6
|
+
export async function createPlanet(fields: PlanetWriteFields): Promise<PlanetModels.PlanetsGetResponseDto> {
|
|
7
|
+
return AppRestClient.post(
|
|
8
|
+
{ resSchema: PlanetModels.PlanetsGetResponseDtoSchema },
|
|
9
|
+
"/api/planets",
|
|
10
|
+
buildPlanetFormData(fields),
|
|
11
|
+
planetFormRequestConfig(),
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function updatePlanet(
|
|
16
|
+
id: string,
|
|
17
|
+
fields: PlanetWriteFields,
|
|
18
|
+
): Promise<PlanetModels.PlanetsGetResponseDto> {
|
|
19
|
+
return AppRestClient.put(
|
|
20
|
+
{ resSchema: PlanetModels.PlanetsGetResponseDtoSchema },
|
|
21
|
+
`/api/planets/${id}`,
|
|
22
|
+
buildPlanetFormData(fields),
|
|
23
|
+
planetFormRequestConfig(),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -282,56 +282,6 @@
|
|
|
282
282
|
},
|
|
283
283
|
"required": ["refreshToken"]
|
|
284
284
|
},
|
|
285
|
-
"MediaUploadRequest": {
|
|
286
|
-
"type": "object",
|
|
287
|
-
"properties": {
|
|
288
|
-
"resourceName": {
|
|
289
|
-
"$ref": "#/components/schemas/MediaResourceName"
|
|
290
|
-
},
|
|
291
|
-
"fileName": {
|
|
292
|
-
"type": "string",
|
|
293
|
-
"minLength": 1
|
|
294
|
-
},
|
|
295
|
-
"fileSize": {
|
|
296
|
-
"type": "integer",
|
|
297
|
-
"minimum": -9007199254740991,
|
|
298
|
-
"maximum": 9007199254740991,
|
|
299
|
-
"exclusiveMinimum": 0
|
|
300
|
-
},
|
|
301
|
-
"mimeType": {
|
|
302
|
-
"type": "string",
|
|
303
|
-
"minLength": 1
|
|
304
|
-
},
|
|
305
|
-
"method": {
|
|
306
|
-
"$ref": "#/components/schemas/MediaUploadMethod"
|
|
307
|
-
}
|
|
308
|
-
},
|
|
309
|
-
"required": ["fileName", "fileSize"]
|
|
310
|
-
},
|
|
311
|
-
"MediaUploadInstructionsResponse": {
|
|
312
|
-
"type": "object",
|
|
313
|
-
"properties": {
|
|
314
|
-
"id": {
|
|
315
|
-
"type": "string"
|
|
316
|
-
},
|
|
317
|
-
"method": {
|
|
318
|
-
"$ref": "#/components/schemas/MediaUploadMethod"
|
|
319
|
-
},
|
|
320
|
-
"url": {
|
|
321
|
-
"type": "string"
|
|
322
|
-
},
|
|
323
|
-
"fields": {
|
|
324
|
-
"type": "array",
|
|
325
|
-
"items": {
|
|
326
|
-
"type": "array"
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
"provider": {
|
|
330
|
-
"type": "string"
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
"required": ["id", "method", "url", "fields"]
|
|
334
|
-
},
|
|
335
285
|
"FakeMailSendDemoBody": {
|
|
336
286
|
"type": "object",
|
|
337
287
|
"properties": {
|
|
@@ -541,13 +491,9 @@
|
|
|
541
491
|
"nullable": true,
|
|
542
492
|
"type": "string"
|
|
543
493
|
},
|
|
544
|
-
"
|
|
545
|
-
"
|
|
546
|
-
"
|
|
547
|
-
{
|
|
548
|
-
"$ref": "#/components/schemas/PlanetImageRequestDto"
|
|
549
|
-
}
|
|
550
|
-
]
|
|
494
|
+
"file": {
|
|
495
|
+
"type": "string",
|
|
496
|
+
"format": "binary"
|
|
551
497
|
}
|
|
552
498
|
},
|
|
553
499
|
"required": ["name"]
|
|
@@ -572,13 +518,12 @@
|
|
|
572
518
|
"nullable": true,
|
|
573
519
|
"type": "string"
|
|
574
520
|
},
|
|
575
|
-
"
|
|
576
|
-
"
|
|
577
|
-
"
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
]
|
|
521
|
+
"file": {
|
|
522
|
+
"type": "string",
|
|
523
|
+
"format": "binary"
|
|
524
|
+
},
|
|
525
|
+
"clearImage": {
|
|
526
|
+
"type": "boolean"
|
|
582
527
|
}
|
|
583
528
|
},
|
|
584
529
|
"required": ["name"]
|
|
@@ -668,15 +613,6 @@
|
|
|
668
613
|
"type": "string",
|
|
669
614
|
"x-enumNames": ["id", "name", "discoveryDate", "createdAt", "updatedAt"]
|
|
670
615
|
},
|
|
671
|
-
"MediaResourceName": {
|
|
672
|
-
"type": "string",
|
|
673
|
-
"minLength": 1,
|
|
674
|
-
"enum": ["small-image", "large-image", "compressed-file", "document", "any", "planet-image"]
|
|
675
|
-
},
|
|
676
|
-
"MediaUploadMethod": {
|
|
677
|
-
"type": "string",
|
|
678
|
-
"minLength": 1
|
|
679
|
-
},
|
|
680
616
|
"FakeMailDemoVariant": {
|
|
681
617
|
"enum": ["text", "html", "recipients", "sequence"],
|
|
682
618
|
"type": "string",
|
|
@@ -774,15 +710,6 @@
|
|
|
774
710
|
}
|
|
775
711
|
},
|
|
776
712
|
"required": ["id", "userId", "name", "createdAt", "updatedAt", "likesCount", "likedByMe"]
|
|
777
|
-
},
|
|
778
|
-
"PlanetImageRequestDto": {
|
|
779
|
-
"type": "object",
|
|
780
|
-
"properties": {
|
|
781
|
-
"id": {
|
|
782
|
-
"type": "string"
|
|
783
|
-
}
|
|
784
|
-
},
|
|
785
|
-
"required": ["id"]
|
|
786
713
|
}
|
|
787
714
|
},
|
|
788
715
|
"securitySchemes": {
|
|
@@ -1209,41 +1136,6 @@
|
|
|
1209
1136
|
"x-bl": "Consumes a valid unused password reset code."
|
|
1210
1137
|
}
|
|
1211
1138
|
},
|
|
1212
|
-
"/api/files/upload-request": {
|
|
1213
|
-
"post": {
|
|
1214
|
-
"operationId": "MediaLibraryController_uploadRequest",
|
|
1215
|
-
"tags": ["Media"],
|
|
1216
|
-
"requestBody": {
|
|
1217
|
-
"required": true,
|
|
1218
|
-
"content": {
|
|
1219
|
-
"application/json": {
|
|
1220
|
-
"schema": {
|
|
1221
|
-
"$ref": "#/components/schemas/MediaUploadRequest"
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
},
|
|
1226
|
-
"responses": {
|
|
1227
|
-
"201": {
|
|
1228
|
-
"description": "OK",
|
|
1229
|
-
"content": {
|
|
1230
|
-
"application/json": {
|
|
1231
|
-
"schema": {
|
|
1232
|
-
"$ref": "#/components/schemas/MediaUploadInstructionsResponse"
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
},
|
|
1238
|
-
"security": [
|
|
1239
|
-
{
|
|
1240
|
-
"bearerAuth": []
|
|
1241
|
-
}
|
|
1242
|
-
],
|
|
1243
|
-
"x-media-upload": true,
|
|
1244
|
-
"x-bl": "Validates an authenticated media upload request, creates a pending media record for an allowed resource, and returns upload instructions for sending the file bytes separately."
|
|
1245
|
-
}
|
|
1246
|
-
},
|
|
1247
1139
|
"/api/fake-mail/demo": {
|
|
1248
1140
|
"post": {
|
|
1249
1141
|
"operationId": "FakeMailController_sendDemo",
|
|
@@ -1391,7 +1283,7 @@
|
|
|
1391
1283
|
"requestBody": {
|
|
1392
1284
|
"required": true,
|
|
1393
1285
|
"content": {
|
|
1394
|
-
"
|
|
1286
|
+
"multipart/form-data": {
|
|
1395
1287
|
"schema": {
|
|
1396
1288
|
"$ref": "#/components/schemas/PlanetsCreateRequestDto"
|
|
1397
1289
|
}
|
|
@@ -1421,7 +1313,7 @@
|
|
|
1421
1313
|
"bearerAuth": []
|
|
1422
1314
|
}
|
|
1423
1315
|
],
|
|
1424
|
-
"x-bl": "Creates a planet owned by the authenticated user
|
|
1316
|
+
"x-bl": "Creates a planet owned by the authenticated user from multipart form fields and an optional image file.",
|
|
1425
1317
|
"x-acl": [
|
|
1426
1318
|
{
|
|
1427
1319
|
"action": "create",
|
|
@@ -1597,7 +1489,7 @@
|
|
|
1597
1489
|
"requestBody": {
|
|
1598
1490
|
"required": true,
|
|
1599
1491
|
"content": {
|
|
1600
|
-
"
|
|
1492
|
+
"multipart/form-data": {
|
|
1601
1493
|
"schema": {
|
|
1602
1494
|
"$ref": "#/components/schemas/PlanetControllerUpdateRequestDto"
|
|
1603
1495
|
}
|
|
@@ -1627,7 +1519,7 @@
|
|
|
1627
1519
|
"bearerAuth": []
|
|
1628
1520
|
}
|
|
1629
1521
|
],
|
|
1630
|
-
"x-bl": "Updates a planet only when the authenticated user owns it, optionally
|
|
1522
|
+
"x-bl": "Updates a planet only when the authenticated user owns it from multipart form fields, optionally replacing or clearing the image, and returns it with creator name and alien name.",
|
|
1631
1523
|
"x-acl": [
|
|
1632
1524
|
{
|
|
1633
1525
|
"action": "update",
|
|
@@ -1797,16 +1689,7 @@
|
|
|
1797
1689
|
{
|
|
1798
1690
|
"name": "Planet",
|
|
1799
1691
|
"x-robodev-hidden": true,
|
|
1800
|
-
"x-robodev-owned-tables": ["Planet", "PlanetLike"]
|
|
1801
|
-
"x-robodev-media-resources": [
|
|
1802
|
-
{
|
|
1803
|
-
"name": "planet-image",
|
|
1804
|
-
"field": "imageId",
|
|
1805
|
-
"dtoField": "image",
|
|
1806
|
-
"mimeTypes": ["image/jpeg", "image/png", "image/webp"],
|
|
1807
|
-
"maxFileSize": 2097152
|
|
1808
|
-
}
|
|
1809
|
-
]
|
|
1692
|
+
"x-robodev-owned-tables": ["Planet", "PlanetLike"]
|
|
1810
1693
|
}
|
|
1811
1694
|
],
|
|
1812
1695
|
"x-robodev-user-roles": [
|