Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.5.0",
"react-router-dom": "^6.30.0"
"react-router-dom": "^6.30.0",
"react-timeago": "^8.3.0"
},
"devDependencies": {
"@7nohe/openapi-react-query-codegen": "^1.6.2",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,38 @@ const state2Color = (state: EdgeWorkerState | null | undefined) => {
}
};

const state2TooltipText = (state: EdgeWorkerState | null | undefined) => {
switch (state) {
// see enum mapping from providers/edge3/src/airflow/providers/edge3/models/edge_worker.py:EdgeWorkerState
case "starting":
return "Edge Worker is in initialization.";
case "running":
return "Edge Worker is actively running a task.";
case "idle":
return "Edge Worker is active and waiting for a task.";
case "shutdown request":
return "Request to shutdown Edge Worker.";
case "terminating":
return "Edge Worker is completing work and stopping.";
case "offline":
return "Edge Worker was shut down.";
case "unknown":
return "No heartbeat signal from worker for some time, Edge Worker probably down.";
case "maintenance request":
return "Worker was requested to enter maintenance mode. Once worker receives this it will pause fetching jobs.";
case "maintenance pending":
return "Edge worker received the request for maintenance, waiting for jobs to finish. Once jobs are finished will move to 'maintenance mode'.";
case "maintenance mode":
return "Edge worker is in maintenance mode. It is online but pauses fetching jobs.";
case "maintenance exit":
return "Request worker to exit maintenance mode. Once the worker receives this state it will un-pause and fetch new jobs.";
case "offline maintenance":
return "Worker was shut down in maintenance mode. It will be in maintenance mode when restarted.";
default:
return undefined;
}
};

export type Props = {
readonly state?: EdgeWorkerState | null;
} & BadgeProps;
Expand All @@ -61,6 +93,7 @@ export const WorkerStateBadge = React.forwardRef<HTMLDivElement, Props>(
px={children === undefined ? 1 : 2}
py={1}
ref={ref}
title={state2TooltipText(state)}
variant="solid"
{...rest}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { useEffect, useState } from "react";

interface ScrollToAnchorProps {
inline?: ScrollLogicalPosition;
block?: ScrollLogicalPosition;
}

export const ScrollToAnchor = ({ block = "start", inline = "nearest" }: ScrollToAnchorProps): null => {
const [hash, setHash] = useState(() => window.location.hash);

useEffect(() => {
const onHashChange = () => setHash(window.location.hash);
window.addEventListener("hashchange", onHashChange);
return () => window.removeEventListener("hashchange", onHashChange);
}, []);

useEffect(() => {
if (hash) {
const element = document.getElementById(hash.slice(1));
if (element) {
element.scrollIntoView({
behavior: "auto",
block: block,
inline: inline,
});
}
}
}, [hash, block, inline]);

return null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@

export * from "./Alert";
export * from "./createToaster";
export * from "./ScrollToAnchor";
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
import { Box, Table } from "@chakra-ui/react";
import { Box, Link, Table } from "@chakra-ui/react";
import { useUiServiceJobs } from "openapi/queries";
import { Link as RouterLink } from "react-router-dom";
import TimeAgo from "react-timeago";

import { ErrorAlert } from "src/components/ErrorAlert";
import { StateBadge } from "src/components/StateBadge";
Expand All @@ -33,8 +35,7 @@ export const JobsPage = () => {
// Use DataTable as component from Airflow-Core UI
// Add sorting
// Add filtering
// Add links to see job details / jobs list
// Translation
// Translation?
if (data)
return (
<Box p={2}>
Expand All @@ -58,18 +59,43 @@ export const JobsPage = () => {
<Table.Row
key={`${job.dag_id}.${job.run_id}.${job.task_id}.${job.map_index}.${job.try_number}`}
>
<Table.Cell>{job.dag_id}</Table.Cell>
<Table.Cell>{job.run_id}</Table.Cell>
<Table.Cell>{job.task_id}</Table.Cell>
<Table.Cell>{job.map_index}</Table.Cell>
<Table.Cell>
{/* TODO Check why <Link to={`/dags/${job.dag_id}`}> is not working via react-router-dom! */}
<Link href={`../dags/${job.dag_id}`}>{job.dag_id}</Link>
</Table.Cell>
<Table.Cell>
<Link href={`../dags/${job.dag_id}/runs/${job.run_id}`}>{job.run_id}</Link>
</Table.Cell>
<Table.Cell>
{job.map_index >= 0 ? (
<Link
href={`../dags/${job.dag_id}/runs/${job.run_id}/tasks/${job.task_id}/mapped/${job.map_index}?try_number=${job.try_number}`}
>
{job.task_id}
</Link>
) : (
<Link
href={`../dags/${job.dag_id}/runs/${job.run_id}/tasks/${job.task_id}?try_number=${job.try_number}`}
>
{job.task_id}
</Link>
)}
</Table.Cell>
<Table.Cell>{job.map_index >= 0 ? job.map_index : "-"}</Table.Cell>
<Table.Cell>{job.try_number}</Table.Cell>
<Table.Cell>
<StateBadge state={job.state}>{job.state}</StateBadge>
</Table.Cell>
<Table.Cell>{job.queue}</Table.Cell>
<Table.Cell>{job.queued_dttm}</Table.Cell>
<Table.Cell>{job.edge_worker}</Table.Cell>
<Table.Cell>{job.last_update}</Table.Cell>
<Table.Cell>
{job.queued_dttm ? <TimeAgo date={job.queued_dttm} live={false} /> : undefined}
</Table.Cell>
<Table.Cell>
<RouterLink to={`/plugin/edge_worker#${job.edge_worker}`}>{job.edge_worker}</RouterLink>
</Table.Cell>
<Table.Cell>
{job.last_update ? <TimeAgo date={job.last_update} live={false} /> : undefined}
</Table.Cell>
</Table.Row>
))}
</Table.Body>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
*/
import { Box, Table } from "@chakra-ui/react";
import { useUiServiceWorker } from "openapi/queries";
import TimeAgo from "react-timeago";

import { ErrorAlert } from "src/components/ErrorAlert";
import { WorkerOperations } from "src/components/WorkerOperations";
import { WorkerStateBadge } from "src/components/WorkerStateBadge";
import { ScrollToAnchor } from "src/components/ui";
import { autoRefreshInterval } from "src/utils";

export const WorkerPage = () => {
Expand All @@ -34,8 +36,9 @@ export const WorkerPage = () => {
// Use DataTable as component from Airflow-Core UI
// Add sorting
// Add filtering
// Add links to see jobs on worker
// Translation
// Add links with filter to see jobs on worker
// Add time zone support for time display
// Translation?
if (data)
return (
<Box p={2}>
Expand All @@ -54,7 +57,7 @@ export const WorkerPage = () => {
</Table.Header>
<Table.Body>
{data.workers.map((worker) => (
<Table.Row key={worker.worker_name}>
<Table.Row key={worker.worker_name} id={worker.worker_name}>
<Table.Cell>{worker.worker_name}</Table.Cell>
<Table.Cell>
<WorkerStateBadge state={worker.state}>{worker.state}</WorkerStateBadge>
Expand All @@ -70,8 +73,12 @@ export const WorkerPage = () => {
"(default)"
)}
</Table.Cell>
<Table.Cell>{worker.first_online}</Table.Cell>
<Table.Cell>{worker.last_heartbeat}</Table.Cell>
<Table.Cell>
{worker.first_online ? <TimeAgo date={worker.first_online} live={false} /> : undefined}
</Table.Cell>
<Table.Cell>
{worker.last_heartbeat ? <TimeAgo date={worker.last_heartbeat} live={false} /> : undefined}
</Table.Cell>
<Table.Cell>{worker.jobs_active}</Table.Cell>
<Table.Cell>
{worker.sysinfo ? (
Expand All @@ -93,6 +100,7 @@ export const WorkerPage = () => {
))}
</Table.Body>
</Table.Root>
<ScrollToAnchor />
</Box>
);
if (error) {
Expand Down
2 changes: 1 addition & 1 deletion providers/edge3/www-hash.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d3d458dbc15ae801bb6bf8f128e38a1a65fd81e3ecc8c87dd30a79acc9a4041a
597e7860a9617d30432916dd89ed0018eca967c71184b4454690e36de31d0120