Skip to content

Commit 8369b78

Browse files
Upstream sync
Merge upstream main into fork main
2 parents ac6a901 + f702a3c commit 8369b78

15 files changed

Lines changed: 443 additions & 101 deletions

File tree

src/api/services/getServiceApi.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import { Service } from "@/pages/ui/services/models/service";
12
import axios from "axios";
23

3-
async function getServiceApi(serviceName:string) {
4+
async function getServiceApi(serviceName:string): Promise<Service> {
45
const response = await axios.get("/system/services/"+serviceName);
56

6-
return response;
7+
return response.data as Service;
78
}
89

910
export default getServiceApi;

src/components/IntegratedApp/index.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,18 @@ function IntegratedApp({
8686

8787
const failedServices = results
8888
.filter((result) => result.status === "rejected")
89-
.map((result) => (result as {
89+
.map((result) => {
90+
const rejectedResult = result as {
9091
status: string;
9192
service: Service;
92-
error: any;
93-
}).service);
93+
error: unknown;
94+
};
95+
96+
return {
97+
service: rejectedResult.service,
98+
message: errorMessage(rejectedResult.error),
99+
};
100+
});
94101

95102
await handleGetServices();
96103

@@ -100,9 +107,11 @@ function IntegratedApp({
100107

101108
if (failedServices.length > 0) {
102109
alert.error(
103-
`Error deleting the following services: ${failedServices
104-
.map((service) => service.name)
105-
.join(", ")}`
110+
failedServices.length === 1
111+
? failedServices[0].message
112+
: failedServices
113+
.map(({ service, message }) => `${service.name}: ${message}`)
114+
.join("\n")
106115
);
107116
}
108117

src/globals.css

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,30 @@ body {
3636
--sidebar-ring: 217.2 91.2% 59.8%;
3737
}
3838
}
39+
40+
.toast-message-scroll {
41+
white-space: pre-line;
42+
display: block;
43+
max-height: 200px;
44+
overflow-y: auto;
45+
scrollbar-width: thin;
46+
scrollbar-color: rgba(20, 20, 20, 0.75) rgba(255, 255, 255, 0.2);
47+
}
48+
49+
.toast-message-scroll::-webkit-scrollbar {
50+
width: 8px;
51+
}
52+
53+
.toast-message-scroll::-webkit-scrollbar-track {
54+
background: rgba(255, 255, 255, 0.2);
55+
border-radius: 999px;
56+
}
57+
58+
.toast-message-scroll::-webkit-scrollbar-thumb {
59+
background: rgba(20, 20, 20, 0.75);
60+
border-radius: 999px;
61+
}
62+
63+
.toast-message-scroll::-webkit-scrollbar-thumb:hover {
64+
background: rgba(20, 20, 20, 0.9);
65+
}

src/hooks/useGetPrivateBuckets.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ import getBucketsApi from "@/api/buckets/getBucketsApi";
22
import { Bucket, Bucket_visibility } from "@/pages/ui/services/models/service";
33
import { useEffect, useState } from "react";
44

5-
function useGetPrivateBuckets() {
5+
function useGetPrivateBuckets(enabled: boolean = true) {
66
const [ buckets, setBuckets ] = useState<Bucket[]>([]);
77

88
useEffect(() => {
9+
if (!enabled) {
10+
return;
11+
}
12+
913
const fetchBuckets = async () => {
1014
const bucketsData = await getBucketsApi();
1115
const filteredBuckets = bucketsData.filter(bucket => (
@@ -14,7 +18,7 @@ function useGetPrivateBuckets() {
1418
setBuckets(filteredBuckets);
1519
};
1620
fetchBuckets();
17-
}, []);
21+
}, [enabled]);
1822

1923
return buckets;
2024
}

src/lib/alert.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,26 @@ import { toast } from "sonner";
55
class ToastAlert {
66
constructor() {}
77

8+
private formatMessage(message: React.ReactNode | string) {
9+
if (typeof message === "string") {
10+
return React.createElement(
11+
"span",
12+
{
13+
className: "toast-message-scroll w-full",
14+
},
15+
message
16+
);
17+
}
18+
19+
return message;
20+
}
21+
822
default(message: React.ReactNode | string) {
9-
toast(message);
23+
toast(this.formatMessage(message));
1024
}
1125

1226
success(message: string) {
13-
toast.success(message, {
27+
toast.success(this.formatMessage(message), {
1428
style: {
1529
backgroundColor: "#17A34B",
1630
color: "white",
@@ -24,7 +38,7 @@ class ToastAlert {
2438
console.error(message);
2539
}
2640

27-
toast.error(message, {
41+
toast.error(this.formatMessage(message), {
2842
style: {
2943
backgroundColor: OscarColors.Red,
3044
color: "white",
@@ -38,7 +52,7 @@ class ToastAlert {
3852
console.warn(messsage);
3953
}
4054

41-
toast.warning(messsage, {
55+
toast.warning(this.formatMessage(messsage), {
4256
style: {
4357
backgroundColor: "orange",
4458
color: "white",

src/pages/ui/hub/components/HubServiceConfPopover/index.tsx

Lines changed: 82 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function HubServiceConfPopover({ roCrateServiceDef, service, isOpen = false, set
3535
const {systemConfig, authData } = useAuth();
3636
const { refreshServices } = useServicesContext();
3737
const [newBucket, setNewBucket] = useState(false);
38-
const buckets = useGetPrivateBuckets();
38+
const buckets = useGetPrivateBuckets(isOpen);
3939

4040
const oidcGroups = getAllowedVOs(systemConfig, authData);
4141
const asyncService = roCrateServiceDef.type.some(t => t.toLowerCase() === "asynchronous");
@@ -90,6 +90,7 @@ function HubServiceConfPopover({ roCrateServiceDef, service, isOpen = false, set
9090
token: "",
9191
enviromentVars: {} as Record<string, string>,
9292
enviromentSecrets: {} as Record<string, string>,
93+
nodePort: "",
9394
});
9495
const [newVolume, setNewVolume] = useState(false);
9596
const [volumes, setVolumes] = useState<ManagedVolume[]>([]);
@@ -119,6 +120,7 @@ function HubServiceConfPopover({ roCrateServiceDef, service, isOpen = false, set
119120
token: false,
120121
enviromentVars: {} as Record<string, boolean>,
121122
enviromentSecrets: {} as Record<string, boolean>,
123+
nodePort: false,
122124
});
123125

124126
useEffect(() => {
@@ -143,6 +145,7 @@ function HubServiceConfPopover({ roCrateServiceDef, service, isOpen = false, set
143145
token: genRandomString(128),
144146
enviromentVars: service.environment?.variables || {},
145147
enviromentSecrets: service.environment?.secrets || {},
148+
nodePort: service.expose?.nodePort || "",
146149
}));
147150
setNewBucket(false);
148151
setVolumes([]);
@@ -158,6 +161,7 @@ function HubServiceConfPopover({ roCrateServiceDef, service, isOpen = false, set
158161
token: false,
159162
enviromentVars: {} as Record<string, boolean>,
160163
enviromentSecrets: {} as Record<string, boolean>,
164+
nodePort: false,
161165
});
162166

163167
let cancelled = false;
@@ -219,6 +223,7 @@ function HubServiceConfPopover({ roCrateServiceDef, service, isOpen = false, set
219223
token: !formData.token,
220224
enviromentVars: Object.fromEntries(Object.entries(formData.enviromentVars).map(([key, value]) => [key, !value || value.length === 0])),
221225
enviromentSecrets: Object.fromEntries(Object.entries(formData.enviromentSecrets).map(([key, value]) => [key, !value || value.length === 0])),
226+
nodePort: !!service?.expose?.nodePort && !formData.nodePort,
222227
};
223228

224229
setErrors(newErrors);
@@ -417,6 +422,22 @@ return (
417422
</SelectContent>
418423
</Select>
419424
</div>
425+
{service?.expose?.nodePort && (
426+
<div>
427+
<Label htmlFor="nodePort">Node Port</Label>
428+
<Input
429+
id="nodePort"
430+
type="number"
431+
placeholder="Enter Node Port"
432+
value={formData.nodePort}
433+
className={errors.nodePort ? "border-red-500 focus:border-red-500" : ""}
434+
onChange={(e) => {
435+
setFormData({ ...formData, nodePort: e.target.value });
436+
if (errors.nodePort) setErrors({ ...errors, nodePort: false });
437+
}}
438+
/>
439+
</div>
440+
)}
420441
{(asyncService || mountBucket) &&
421442
<div>
422443
<Label>Bucket</Label>
@@ -584,55 +605,69 @@ return (
584605
</div>
585606
</div>
586607
}
587-
{formData?.enviromentVars && Object.entries(formData.enviromentVars).map(([key, value]) => (
588-
<div key={`var-${key}`}>
589-
<Label>{key}</Label>
590-
<Input
591-
disabled={ifEndpointService(key, value, formData.name) !== value}
592-
type="input"
593-
value={ifEndpointService(key, value, formData.name)}
594-
style={{ width: "100%",
595-
fontWeight: "normal",
596-
}}
597-
onChange={(e) => {
598-
setFormData((prev) => ({
599-
...prev,
600-
enviromentVars: {
601-
...prev.enviromentVars,
602-
[key]: e.target.value,
603-
},
604-
}));
605-
if (errors.enviromentVars && errors.enviromentVars[key]) setErrors({ ...errors, enviromentVars: { ...errors.enviromentVars, [key]: false } });
606-
}}
607-
placeholder={`Enter ${key}`}
608-
className={errors.enviromentVars[key] ? "border-red-500 focus:border-red-500" : ""}
609-
/>
608+
{Object.keys(formData?.enviromentVars ?? {}).length > 0 && (
609+
<div>
610+
<Label>Environment Variables</Label>
611+
<hr className="mb-2"/>
612+
613+
{Object.entries(formData.enviromentVars).map(([key, value]) => (
614+
<div key={`var-${key}`}>
615+
<Label>{key}</Label>
616+
<Input
617+
disabled={ifEndpointService(key, value, formData.name) !== value}
618+
type="input"
619+
value={ifEndpointService(key, value, formData.name)}
620+
style={{ width: "100%",
621+
fontWeight: "normal",
622+
}}
623+
onChange={(e) => {
624+
setFormData((prev) => ({
625+
...prev,
626+
enviromentVars: {
627+
...prev.enviromentVars,
628+
[key]: e.target.value,
629+
},
630+
}));
631+
if (errors.enviromentVars && errors.enviromentVars[key]) setErrors({ ...errors, enviromentVars: { ...errors.enviromentVars, [key]: false } });
632+
}}
633+
placeholder={`Enter ${key}`}
634+
className={errors.enviromentVars[key] ? "border-red-500 focus:border-red-500" : ""}
635+
/>
636+
</div>
637+
))}
610638
</div>
611-
))}
612-
{formData?.enviromentSecrets && Object.entries(formData.enviromentSecrets).map(([key, value]) => (
613-
<div key={`secret-${key}`}>
614-
<Label>{key}</Label>
615-
<Input
616-
type="password"
617-
value={value}
618-
style={{ width: "100%",
619-
fontWeight: "normal",
639+
)}
640+
{Object.keys(formData?.enviromentSecrets ?? {}).length > 0 && (
641+
<div>
642+
<Label>Environment Secrets</Label>
643+
<hr className="mb-2"/>
644+
645+
{Object.entries(formData.enviromentSecrets).map(([key, value]) => (
646+
<div key={`secret-${key}`}>
647+
<Label>{key}</Label>
648+
<Input
649+
type="password"
650+
value={value}
651+
style={{ width: "100%",
652+
fontWeight: "normal",
653+
}}
654+
onChange={(e) => {
655+
setFormData((prev) => ({
656+
...prev,
657+
enviromentSecrets: {
658+
...prev.enviromentSecrets,
659+
[key]: e.target.value,
660+
},
661+
}));
662+
if (errors.enviromentSecrets && errors.enviromentSecrets[key]) setErrors({ ...errors, enviromentSecrets: { ...errors.enviromentSecrets, [key]: false } });
620663
}}
621-
onChange={(e) => {
622-
setFormData((prev) => ({
623-
...prev,
624-
enviromentSecrets: {
625-
...prev.enviromentSecrets,
626-
[key]: e.target.value,
627-
},
628-
}));
629-
if (errors.enviromentSecrets && errors.enviromentSecrets[key]) setErrors({ ...errors, enviromentSecrets: { ...errors.enviromentSecrets, [key]: false } });
630-
}}
631-
placeholder={`Enter ${key}`}
632-
className={errors.enviromentSecrets[key] ? "border-red-500 focus:border-red-500" : ""}
633-
/>
664+
placeholder={`Enter ${key}`}
665+
className={errors.enviromentSecrets[key] ? "border-red-500 focus:border-red-500" : ""}
666+
/>
667+
</div>
668+
))}
634669
</div>
635-
))}
670+
)}
636671
</div>
637672
<DialogFooter>
638673
<RequestButton className="grid grid-cols-[auto] sm:grid-cols-1 gap-2" variant={"mainGreen"} request={handleDeploy}>

src/pages/ui/services/components/FDL/utils/yamlToService.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import YAML from "yaml";
2-
import { Service } from "../../../models/service";
2+
import { Service, ServiceVisibility } from "../../../models/service";
33
import { alert } from "@/lib/alert";
44
import { errorMessage } from "@/lib/error";
55

@@ -15,6 +15,11 @@ const yamlToServices = (fdlString: string, scriptString: string) => {
1515
serviceParams.script = scriptContent;
1616
serviceParams.storage_providers = obj.storage_providers || {};
1717
serviceParams.clusters = obj.clusters || {};
18+
serviceParams.visibility = serviceParams.visibility ?? ServiceVisibility.private;
19+
serviceParams.allowed_users =
20+
serviceParams.visibility === ServiceVisibility.restricted
21+
? serviceParams.allowed_users ?? []
22+
: [];
1823
services.push(serviceParams);
1924
});
2025
}

0 commit comments

Comments
 (0)