mirror of
https://github.com/vale981/ray
synced 2025-03-06 02:21:39 -05:00
Actor Search Bar in Logical View (#8865)
This commit is contained in:
parent
439dbb7822
commit
950b389581
4 changed files with 127 additions and 80 deletions
|
@ -109,6 +109,38 @@ export type NodeInfoResponse = {
|
|||
|
||||
export const getNodeInfo = () => get<NodeInfoResponse>("/api/node_info", {});
|
||||
|
||||
export type RayletActorInfo =
|
||||
| {
|
||||
actorId: string;
|
||||
actorTitle: string;
|
||||
averageTaskExecutionSpeed: number;
|
||||
children: RayletInfoResponse["actors"];
|
||||
// currentTaskFuncDesc: string[];
|
||||
ipAddress: string;
|
||||
jobId: string;
|
||||
nodeId: string;
|
||||
numExecutedTasks: number;
|
||||
numLocalObjects: number;
|
||||
numObjectIdsInScope: number;
|
||||
pid: number;
|
||||
port: number;
|
||||
state: 0 | 1 | 2;
|
||||
taskQueueLength: number;
|
||||
timestamp: number;
|
||||
usedObjectStoreMemory: number;
|
||||
usedResources: { [key: string]: number };
|
||||
currentTaskDesc?: string;
|
||||
numPendingTasks?: number;
|
||||
webuiDisplay?: Record<string, string>;
|
||||
}
|
||||
| {
|
||||
actorId: string;
|
||||
actorTitle: string;
|
||||
requiredResources: { [key: string]: number };
|
||||
state: -1;
|
||||
invalidStateType?: "infeasibleActor" | "pendingActor";
|
||||
};
|
||||
|
||||
export type RayletInfoResponse = {
|
||||
nodes: {
|
||||
[ip: string]: {
|
||||
|
@ -120,37 +152,7 @@ export type RayletInfoResponse = {
|
|||
};
|
||||
};
|
||||
actors: {
|
||||
[actorId: string]:
|
||||
| {
|
||||
actorId: string;
|
||||
actorTitle: string;
|
||||
averageTaskExecutionSpeed: number;
|
||||
children: RayletInfoResponse["actors"];
|
||||
// currentTaskFuncDesc: string[];
|
||||
ipAddress: string;
|
||||
jobId: string;
|
||||
nodeId: string;
|
||||
numExecutedTasks: number;
|
||||
numLocalObjects: number;
|
||||
numObjectIdsInScope: number;
|
||||
pid: number;
|
||||
port: number;
|
||||
state: 0 | 1 | 2;
|
||||
taskQueueLength: number;
|
||||
timestamp: number;
|
||||
usedObjectStoreMemory: number;
|
||||
usedResources: { [key: string]: number };
|
||||
currentTaskDesc?: string;
|
||||
numPendingTasks?: number;
|
||||
webuiDisplay?: Record<string, string>;
|
||||
}
|
||||
| {
|
||||
actorId: string;
|
||||
actorTitle: string;
|
||||
requiredResources: { [key: string]: number };
|
||||
state: -1;
|
||||
invalidStateType?: "infeasibleActor" | "pendingActor";
|
||||
};
|
||||
[actorId: string]: RayletActorInfo;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
getProfilingResultURL,
|
||||
launchKillActor,
|
||||
launchProfiling,
|
||||
RayletInfoResponse,
|
||||
RayletActorInfo,
|
||||
} from "../../../api";
|
||||
import Actors from "./Actors";
|
||||
|
||||
|
@ -61,7 +61,7 @@ const styles = (theme: Theme) =>
|
|||
});
|
||||
|
||||
type Props = {
|
||||
actor: RayletInfoResponse["actors"][keyof RayletInfoResponse["actors"]];
|
||||
actor: RayletActorInfo;
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import { createStyles, Theme, withStyles, WithStyles } from "@material-ui/core";
|
||||
import React from "react";
|
||||
import React, { Fragment } from "react";
|
||||
import { RayletInfoResponse } from "../../../api";
|
||||
import Actor from "./Actor";
|
||||
|
||||
const styles = (theme: Theme) => createStyles({});
|
||||
|
||||
type Props = {
|
||||
type ActorProps = {
|
||||
actors: RayletInfoResponse["actors"];
|
||||
};
|
||||
|
||||
class Actors extends React.Component<Props & WithStyles<typeof styles>> {
|
||||
render() {
|
||||
const { actors } = this.props;
|
||||
return Object.entries(actors).map(([actorId, actor]) => (
|
||||
<Actor actor={actor} key={actorId} />
|
||||
));
|
||||
}
|
||||
}
|
||||
const Actors = (props: ActorProps) => {
|
||||
const { actors } = props;
|
||||
|
||||
export default withStyles(styles)(Actors);
|
||||
const actorChildren = Object.entries(actors).map(([actorId, actor]) => (
|
||||
<Actor actor={actor} key={actorId} />
|
||||
));
|
||||
return <Fragment>{actorChildren}</Fragment>;
|
||||
};
|
||||
|
||||
export default Actors;
|
||||
|
|
|
@ -1,48 +1,96 @@
|
|||
import {
|
||||
createStyles,
|
||||
Theme,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
Input,
|
||||
InputLabel,
|
||||
Typography,
|
||||
WithStyles,
|
||||
withStyles,
|
||||
} from "@material-ui/core";
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { RayletActorInfo, RayletInfoResponse } from "../../../api";
|
||||
import { StoreState } from "../../../store";
|
||||
import Actors from "./Actors";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
warning: {
|
||||
fontSize: "0.8125rem",
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
warningIcon: {
|
||||
fontSize: "1.25em",
|
||||
verticalAlign: "text-bottom",
|
||||
},
|
||||
});
|
||||
const actorMatchesSearch = (
|
||||
actor: RayletActorInfo,
|
||||
nameFilter: string,
|
||||
): boolean => {
|
||||
// Performs a case insensitive search for the name filter string within the
|
||||
// actor and all of its nested subactors.
|
||||
const actorTitles = getNestedActorTitles(actor);
|
||||
const loweredNameFilter = nameFilter.toLowerCase();
|
||||
const match = actorTitles.find(
|
||||
(actorTitle) => actorTitle.toLowerCase().search(loweredNameFilter) !== -1,
|
||||
);
|
||||
return match !== undefined;
|
||||
};
|
||||
|
||||
const getNestedActorTitles = (actor: RayletActorInfo): string[] => {
|
||||
const actorTitle = actor.actorTitle;
|
||||
const titles: string[] = actorTitle ? [actorTitle] : [];
|
||||
// state of -1 indicates an actor data record that does not have children.
|
||||
if (actor.state === -1) {
|
||||
return titles;
|
||||
}
|
||||
const children = actor["children"];
|
||||
if (children === undefined || Object.entries(children).length === 0) {
|
||||
return titles;
|
||||
}
|
||||
const childrenTitles = Object.values(children).flatMap((actor) =>
|
||||
getNestedActorTitles(actor),
|
||||
);
|
||||
return titles.concat(childrenTitles);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
rayletInfo: state.dashboard.rayletInfo,
|
||||
});
|
||||
|
||||
class LogicalView extends React.Component<
|
||||
WithStyles<typeof styles> & ReturnType<typeof mapStateToProps>
|
||||
> {
|
||||
render() {
|
||||
const { rayletInfo } = this.props;
|
||||
return (
|
||||
<div>
|
||||
{rayletInfo === null ? (
|
||||
<Typography color="textSecondary">Loading...</Typography>
|
||||
) : Object.entries(rayletInfo.actors).length === 0 ? (
|
||||
<Typography color="textSecondary">No actors found.</Typography>
|
||||
) : (
|
||||
<Actors actors={rayletInfo.actors} />
|
||||
)}
|
||||
</div>
|
||||
const filterObj = (obj: Object, filterFn: any) =>
|
||||
Object.fromEntries(Object.entries(obj).filter(filterFn));
|
||||
|
||||
type LogicalViewProps = {
|
||||
rayletInfo: RayletInfoResponse | null;
|
||||
} & ReturnType<typeof mapStateToProps>;
|
||||
|
||||
const LogicalView = ({ rayletInfo }: LogicalViewProps) => {
|
||||
const [nameFilter, setNameFilter] = useState("");
|
||||
|
||||
if (rayletInfo === null) {
|
||||
return <Typography color="textSecondary">Loading...</Typography>;
|
||||
}
|
||||
let filteredActors = rayletInfo.actors;
|
||||
if (nameFilter !== "") {
|
||||
filteredActors = filterObj(
|
||||
filteredActors,
|
||||
([_, actor]: [any, RayletActorInfo]) =>
|
||||
actorMatchesSearch(actor, nameFilter),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(withStyles(styles)(LogicalView));
|
||||
return (
|
||||
<div>
|
||||
{Object.entries(rayletInfo.actors).length === 0 ? (
|
||||
<Typography color="textSecondary">No actors found.</Typography>
|
||||
) : (
|
||||
<div>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="actor-name-filter">Actor Search</InputLabel>
|
||||
<Input
|
||||
id="actor-name-filter"
|
||||
aria-describedby="actor-name-helper-text"
|
||||
value={nameFilter}
|
||||
onChange={(event) => setNameFilter(event.target.value)}
|
||||
/>
|
||||
<FormHelperText id="actor-name-helper-text">
|
||||
Search for an actor by name
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<Actors actors={filteredActors} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(LogicalView);
|
||||
|
|
Loading…
Add table
Reference in a new issue