Skip to content

Commit 48c824a

Browse files
authored
Feature/add state badge to edge react UI (#54993)
* Add colored status badge to Edge Worker react UI * Remove outdated comment after eslint exception was removed
1 parent f5d0b17 commit 48c824a

File tree

8 files changed

+266
-23
lines changed

8 files changed

+266
-23
lines changed

providers/edge3/src/airflow/providers/edge3/plugins/www/dist/main.umd.cjs

Lines changed: 17 additions & 17 deletions
Large diffs are not rendered by default.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*!
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
import { Badge, type BadgeProps } from "@chakra-ui/react";
20+
import type { TaskInstanceState } from "openapi/requests/types.gen";
21+
import * as React from "react";
22+
23+
import { StateIcon } from "./StateIcon";
24+
25+
export type Props = {
26+
readonly state?: TaskInstanceState | null;
27+
} & BadgeProps;
28+
29+
export const StateBadge = React.forwardRef<HTMLDivElement, Props>(({ children, state, ...rest }, ref) => (
30+
<Badge
31+
borderRadius="full"
32+
colorPalette={state === null ? "none" : state}
33+
fontSize="sm"
34+
px={children === undefined ? 1 : 2}
35+
py={1}
36+
ref={ref}
37+
variant="solid"
38+
{...rest}
39+
>
40+
{state === undefined ? undefined : <StateIcon state={state} />}
41+
{children}
42+
</Badge>
43+
));
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*!
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
import type { TaskInstanceState } from "openapi/requests/types.gen";
20+
import type { IconBaseProps } from "react-icons";
21+
import { FiActivity, FiCalendar, FiRepeat, FiSkipForward, FiSlash, FiWatch, FiX } from "react-icons/fi";
22+
import { LuCalendarSync, LuCheck, LuCircleDashed, LuCircleFadingArrowUp, LuRedo2 } from "react-icons/lu";
23+
import { PiQueue } from "react-icons/pi";
24+
25+
type Props = {
26+
readonly state?: TaskInstanceState | null;
27+
} & IconBaseProps;
28+
29+
export const StateIcon = ({ state, ...rest }: Props) => {
30+
switch (state) {
31+
case "deferred":
32+
return <FiWatch {...rest} />;
33+
case "failed":
34+
return <FiX {...rest} />;
35+
case "queued":
36+
return <PiQueue {...rest} />;
37+
case "removed":
38+
return <FiSlash {...rest} />;
39+
case "restarting":
40+
return <FiRepeat {...rest} />;
41+
case "running":
42+
return <FiActivity {...rest} />;
43+
case "scheduled":
44+
return <FiCalendar {...rest} />;
45+
case "skipped":
46+
return <FiSkipForward {...rest} />;
47+
case "success":
48+
return <LuCheck {...rest} />;
49+
case "up_for_reschedule":
50+
return <LuCalendarSync {...rest} />;
51+
case "up_for_retry":
52+
return <LuRedo2 {...rest} />;
53+
case "upstream_failed":
54+
return <LuCircleFadingArrowUp {...rest} />;
55+
default:
56+
return <LuCircleDashed {...rest} />;
57+
}
58+
};
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*!
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
import { Badge, type BadgeProps } from "@chakra-ui/react";
20+
import type { EdgeWorkerState } from "openapi/requests/types.gen";
21+
import * as React from "react";
22+
23+
import { WorkerStateIcon } from "./WorkerStateIcon";
24+
25+
const state2Color = (state: EdgeWorkerState | null | undefined) => {
26+
switch (state) {
27+
case "starting":
28+
case "maintenance request":
29+
case "maintenance exit":
30+
return "yellow";
31+
case "running":
32+
return "green";
33+
case "idle":
34+
return "teal";
35+
case "shutdown request":
36+
case "terminating":
37+
return "purple";
38+
case "offline":
39+
case "offline maintenance":
40+
return "black";
41+
case "unknown":
42+
return "red";
43+
case "maintenance mode":
44+
case "maintenance pending":
45+
return "orange";
46+
default:
47+
return "gray";
48+
}
49+
};
50+
51+
export type Props = {
52+
readonly state?: EdgeWorkerState | null;
53+
} & BadgeProps;
54+
55+
export const WorkerStateBadge = React.forwardRef<HTMLDivElement, Props>(
56+
({ children, state, ...rest }, ref) => (
57+
<Badge
58+
borderRadius="full"
59+
colorPalette={state2Color(state)}
60+
fontSize="sm"
61+
px={children === undefined ? 1 : 2}
62+
py={1}
63+
ref={ref}
64+
variant="solid"
65+
{...rest}
66+
>
67+
{state === undefined ? undefined : <WorkerStateIcon state={state} />}
68+
{children}
69+
</Badge>
70+
),
71+
);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*!
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
import type { EdgeWorkerState } from "openapi/requests/types.gen";
20+
import type { IconBaseProps } from "react-icons";
21+
import { BiSolidLeaf } from "react-icons/bi";
22+
import { FiActivity, FiArrowDownRight, FiWatch } from "react-icons/fi";
23+
import { HiOutlineWrench, HiOutlineWrenchScrewdriver } from "react-icons/hi2";
24+
import { IoCloudOfflineOutline } from "react-icons/io5";
25+
import { LuCircleDashed } from "react-icons/lu";
26+
import { RiWifiOffLine } from "react-icons/ri";
27+
28+
type Props = {
29+
readonly state?: EdgeWorkerState | null;
30+
} & IconBaseProps;
31+
32+
export const WorkerStateIcon = ({ state, ...rest }: Props) => {
33+
switch (state) {
34+
case "starting":
35+
return <FiWatch {...rest} />;
36+
case "running":
37+
return <FiActivity {...rest} />;
38+
case "idle":
39+
return <BiSolidLeaf {...rest} />;
40+
case "shutdown request":
41+
case "terminating":
42+
return <FiArrowDownRight {...rest} />;
43+
case "offline":
44+
return <IoCloudOfflineOutline {...rest} />;
45+
case "unknown":
46+
return <RiWifiOffLine {...rest} />;
47+
case "maintenance request":
48+
case "maintenance pending":
49+
case "maintenance exit":
50+
return <HiOutlineWrench {...rest} />;
51+
case "maintenance mode":
52+
case "offline maintenance":
53+
return <HiOutlineWrenchScrewdriver {...rest} />;
54+
default:
55+
return <LuCircleDashed {...rest} />;
56+
}
57+
};

providers/edge3/src/airflow/providers/edge3/plugins/www/src/pages/JobsPage.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { Box, Table } from "@chakra-ui/react";
2020
import { useUiServiceJobs } from "openapi/queries";
2121

2222
import { ErrorAlert } from "src/components/ErrorAlert";
23+
import { StateBadge } from "src/components/StateBadge";
2324
import { autoRefreshInterval } from "src/utils";
2425

2526
export const JobsPage = () => {
@@ -29,7 +30,6 @@ export const JobsPage = () => {
2930
});
3031

3132
// TODO to make it proper
32-
// Beautification of state like in Airflow 2
3333
// Use DataTable as component from Airflow-Core UI
3434
// Add sorting
3535
// Add filtering
@@ -63,7 +63,9 @@ export const JobsPage = () => {
6363
<Table.Cell>{job.task_id}</Table.Cell>
6464
<Table.Cell>{job.map_index}</Table.Cell>
6565
<Table.Cell>{job.try_number}</Table.Cell>
66-
<Table.Cell>{job.state}</Table.Cell>
66+
<Table.Cell>
67+
<StateBadge state={job.state}>{job.state}</StateBadge>
68+
</Table.Cell>
6769
<Table.Cell>{job.queue}</Table.Cell>
6870
<Table.Cell>{job.queued_dttm}</Table.Cell>
6971
<Table.Cell>{job.edge_worker}</Table.Cell>

providers/edge3/src/airflow/providers/edge3/plugins/www/src/pages/WorkerPage.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { Box, Table } from "@chakra-ui/react";
2020
import { useUiServiceWorker } from "openapi/queries";
2121

2222
import { ErrorAlert } from "src/components/ErrorAlert";
23+
import { WorkerStateBadge } from "src/components/WorkerStateBadge";
2324
import { autoRefreshInterval } from "src/utils";
2425

2526
export const WorkerPage = () => {
@@ -29,7 +30,6 @@ export const WorkerPage = () => {
2930
});
3031

3132
// TODO to make it proper
32-
// Beautification of state like in Airflow 2
3333
// Use DataTable as component from Airflow-Core UI
3434
// Add actions for maintenance / delete of orphan worker
3535
// Add sorting
@@ -56,8 +56,20 @@ export const WorkerPage = () => {
5656
{data.workers.map((worker) => (
5757
<Table.Row key={worker.worker_name}>
5858
<Table.Cell>{worker.worker_name}</Table.Cell>
59-
<Table.Cell>{worker.state}</Table.Cell>
60-
<Table.Cell>{worker.queues}</Table.Cell>
59+
<Table.Cell>
60+
<WorkerStateBadge state={worker.state}>{worker.state}</WorkerStateBadge>
61+
</Table.Cell>
62+
<Table.Cell>
63+
{worker.queues ? (
64+
<ul>
65+
{worker.queues.map((queue) => (
66+
<li key={queue}>{queue}</li>
67+
))}
68+
</ul>
69+
) : (
70+
"(default)"
71+
)}
72+
</Table.Cell>
6173
<Table.Cell>{worker.first_online}</Table.Cell>
6274
<Table.Cell>{worker.last_heartbeat}</Table.Cell>
6375
<Table.Cell>{worker.jobs_active}</Table.Cell>

providers/edge3/www-hash.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
33ac5e99982b8cf9795aff82a9b08baf5a5c2d13d71d1be72a5ffd664f8e14c1
1+
d780858c70355a081b2486871c18d5f3c579f04129b3b15e7c6f691a1a3a2c12

0 commit comments

Comments
 (0)