Skip to content

Commit 50fceec

Browse files
committed
Merge branch 'main' into feat
2 parents 80255c4 + 670e7ca commit 50fceec

File tree

5 files changed

+181
-3
lines changed

5 files changed

+181
-3
lines changed

src/Components/Event/EventCard.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Indicator } from "../Home/Indicator";
66
import { EventStatus, IsIncident } from "./Enums";
77
import { EventAffected } from "./EventAffected";
88
import { EventEditor } from "./EventEditor";
9+
import { EventExtract } from "./EventExtract";
910

1011
/**
1112
* Represents an EventCard component that displays detailed information about a specific event.
@@ -37,7 +38,13 @@ export function EventCard({ Event }: { Event: Models.IEvent }) {
3738
</div>
3839

3940
<Authorized>
40-
<EventEditor Event={Event} />
41+
<div className="flex gap-x-3">
42+
{
43+
Event.RegionServices.size > 1 &&
44+
<EventExtract Event={Event} />
45+
}
46+
<EventEditor Event={Event} />
47+
</div>
4148
</Authorized>
4249
</div>
4350

src/Components/Event/EventExtract.tsx

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { ScaleButton, ScaleHelperText, ScaleIconActionExport, ScaleModal, ScaleTable } from "@telekom/scale-components-react";
2+
import { useBoolean } from "ahooks";
3+
import { chain } from "lodash";
4+
import { Models } from "~/Services/Status.Models";
5+
import { useEventExtract } from "./useEventExtract";
6+
7+
/**
8+
* @author Aloento
9+
* @since 1.0.0
10+
* @version 0.1.0
11+
*/
12+
export function EventExtract({ Event }: { Event: Models.IEvent }) {
13+
const { services, setServices, valServices, OnSubmit, Loading } = useEventExtract(Event);
14+
const [open, { setTrue, setFalse }] = useBoolean();
15+
16+
return <>
17+
<ScaleButton onClick={setTrue} size="small" variant="secondary">
18+
<ScaleIconActionExport />
19+
Extract
20+
</ScaleButton>
21+
22+
<ScaleModal
23+
heading="Extract Event"
24+
opened={open}
25+
omitCloseButton
26+
size="small"
27+
class="absolute"
28+
onScale-before-close={(e) => e.preventDefault()}
29+
>
30+
<form
31+
className="flex flex-col gap-y-6"
32+
autoComplete="off"
33+
onSubmit={(e) => {
34+
e.preventDefault();
35+
OnSubmit().then((ok) => ok && setFalse());
36+
}}>
37+
<ScaleTable>
38+
<div className="max-h-96 overflow-auto">
39+
<table>
40+
<thead className="sticky">
41+
<tr>
42+
<th />
43+
<th>Service Name</th>
44+
<th>Region</th>
45+
</tr>
46+
</thead>
47+
48+
<tbody>
49+
{chain([...Event.RegionServices])
50+
.orderBy(x => x.Service.Name)
51+
.map((x, i) =>
52+
<tr key={i}>
53+
<td>
54+
<input
55+
type="checkbox"
56+
onChange={(e) => {
57+
const checked = e.target.checked;
58+
setServices((curr) => {
59+
if (checked) {
60+
return [...curr, x];
61+
}
62+
63+
return curr.filter(s => s !== x);
64+
})
65+
}}
66+
/>
67+
</td>
68+
69+
<td>{x.Service.Name}</td>
70+
<td>{x.Region.Name}</td>
71+
</tr>)
72+
.value()}
73+
</tbody>
74+
</table>
75+
</div>
76+
77+
<ScaleHelperText
78+
variant={valServices ? "danger" : "informational"}
79+
helperText={valServices || `Selected ${services.length} services`}
80+
/>
81+
</ScaleTable>
82+
83+
<div className="flex gap-x-3 self-end">
84+
<ScaleButton onClick={setFalse} variant="secondary" type="button">
85+
Cancel
86+
</ScaleButton>
87+
88+
<ScaleButton type="submit" disabled={Loading}>
89+
Submit
90+
</ScaleButton>
91+
</div>
92+
</form>
93+
</ScaleModal>
94+
</>;
95+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { useRequest } from "ahooks";
2+
import { useState } from "react";
3+
import { useStatus } from "~/Services/Status";
4+
import { Models } from "~/Services/Status.Models";
5+
import { useAccessToken } from "../Auth/useAccessToken";
6+
import { useRouter } from "../Router";
7+
8+
/**
9+
* @author Aloento
10+
* @since 1.0.0
11+
* @version 0.1.0
12+
*/
13+
export function useEventExtract(event: Models.IEvent) {
14+
const [services, _setServices] = useState<Models.IRegionService[]>([]);
15+
const [valServices, setValServices] = useState<string>();
16+
function setServices(action: (curr: Models.IRegionService[]) => Models.IRegionService[] = (s) => s) {
17+
const updated = action(services);
18+
let err: boolean = false;
19+
20+
if (!updated || !updated.length) {
21+
setValServices("At least one service is required.");
22+
err = true;
23+
}
24+
25+
_setServices(updated);
26+
!err && setValServices(undefined);
27+
28+
return !err;
29+
}
30+
31+
const getToken = useAccessToken();
32+
const { Nav } = useRouter();
33+
const { Refresh } = useStatus();
34+
35+
const { runAsync, loading } = useRequest(async () => {
36+
if (!setServices()) {
37+
return false;
38+
}
39+
40+
const url = process.env.SD_BACKEND_URL!;
41+
42+
const body: Record<string, any> = {
43+
components: services.map(s => s.Id),
44+
}
45+
46+
const raw = await fetch(`${url}/v2/incidents/${event.Id}/extract`, {
47+
method: "POST",
48+
headers: {
49+
"Content-Type": "application/json",
50+
"Authorization": `Bearer ${getToken()}`
51+
},
52+
body: JSON.stringify(body)
53+
});
54+
55+
const res = await raw.json();
56+
const id = res.id;
57+
58+
if (id) {
59+
await Refresh();
60+
Nav(`/Event/${id}`);
61+
}
62+
63+
return true;
64+
}, {
65+
manual: true
66+
});
67+
68+
return {
69+
services,
70+
setServices,
71+
valServices,
72+
OnSubmit: runAsync,
73+
Loading: loading
74+
}
75+
}

src/Components/New/useNewForm.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export function useNewForm() {
150150
const getToken = useAccessToken();
151151

152152
const { runAsync, loading } = useRequest(async () => {
153-
if (![setTitle(), setType(), setDescription(), setStart, setEnd(), setServices()].every(Boolean)) {
153+
if (![setTitle(), setType(), setDescription(), setStart(), setEnd(), setServices()].every(Boolean)) {
154154
return;
155155
}
156156

src/Services/Status.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const db = new DB(EmptyDB);
3636
interface IContext {
3737
DB: IStatusContext;
3838
Update: (data?: IStatusContext) => void;
39+
Refresh: () => Promise<unknown>;
3940
}
4041

4142
const CTX = createContext<IContext>({} as IContext);
@@ -138,6 +139,6 @@ export function StatusContext({ children }: { children: JSX.Element }) {
138139
}
139140

140141
return (
141-
<CTX.Provider value={{ DB: ins, Update: update }}>{children}</CTX.Provider>
142+
<CTX.Provider value={{ DB: ins, Update: update, Refresh: runAsync }}>{children}</CTX.Provider>
142143
);
143144
}

0 commit comments

Comments
 (0)