-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update layout of serve page to be deployments first #42079
Changes from all commits
328d161
4a6fb3f
bbaf4d0
86e6e72
0c8d8c8
3cf8401
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,42 @@ | ||
import { render, screen } from "@testing-library/react"; | ||
import React from "react"; | ||
import { ServeApplication, ServeApplicationStatus } from "../type/serve"; | ||
import { ServeDeployment, ServeDeploymentStatus } from "../type/serve"; | ||
import { ServeStatusIcon } from "./ServeStatus"; | ||
|
||
const APP: ServeApplication = { | ||
name: "MyServeApp", | ||
route_prefix: "/my-serve-app", | ||
docs_path: null, | ||
status: ServeApplicationStatus.RUNNING, | ||
message: "", | ||
last_deployed_time_s: 1682029771.0748637, | ||
deployed_app_config: null, | ||
deployments: {}, | ||
const DEPLOYMENT: ServeDeployment = { | ||
name: "MyServeDeployment", | ||
deployment_config: {} as any, | ||
message: "Running", | ||
replicas: [], | ||
status: ServeDeploymentStatus.HEALTHY, | ||
}; | ||
|
||
describe("ServeStatusIcon", () => { | ||
it("renders RUNNING status", async () => { | ||
render(<ServeStatusIcon app={APP} small={false} />); | ||
it("renders HEALTHY status", async () => { | ||
render(<ServeStatusIcon deployment={DEPLOYMENT} small={false} />); | ||
|
||
await screen.findByTestId("serve-status-icon"); | ||
|
||
const icon = screen.getByTestId("serve-status-icon"); | ||
const classList = icon.getAttribute("class"); | ||
expect(classList).toContain("colorSuccess"); | ||
await screen.findByTitle("Healthy"); | ||
}); | ||
|
||
it("renders NOT_STARTED status", async () => { | ||
it("renders UNHEALTHY status", async () => { | ||
render( | ||
<ServeStatusIcon | ||
app={{ ...APP, status: ServeApplicationStatus.NOT_STARTED }} | ||
deployment={{ ...DEPLOYMENT, status: ServeDeploymentStatus.UNHEALTHY }} | ||
small={false} | ||
/>, | ||
); | ||
|
||
await screen.findByTestId("serve-status-icon"); | ||
|
||
expect(screen.queryByTestId("serve-status-icon")).not.toHaveClass( | ||
"colorSuccess", | ||
); | ||
expect(screen.queryByTestId("serve-status-icon")).not.toHaveClass( | ||
"colorError", | ||
); | ||
await screen.findByTitle("Unhealthy"); | ||
}); | ||
|
||
it("renders DEPLOY_FAILED status", async () => { | ||
it("renders UPDATING status", async () => { | ||
render( | ||
<ServeStatusIcon | ||
app={{ ...APP, status: ServeApplicationStatus.DEPLOY_FAILED }} | ||
deployment={{ ...DEPLOYMENT, status: ServeDeploymentStatus.UPDATING }} | ||
small={false} | ||
/>, | ||
); | ||
|
||
await screen.findByTestId("serve-status-icon"); | ||
|
||
const icon = screen.getByTestId("serve-status-icon"); | ||
const classList = icon.getAttribute("class"); | ||
expect(classList).toContain("colorError"); | ||
await screen.findByTitle("Updating"); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
export type ClassNameProps = { | ||
className?: string; | ||
}; | ||
|
||
export type DataTestIdProps = { | ||
"data-testid"?: string; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ import _ from "lodash"; | |
import React from "react"; | ||
import { ServeStatusIcon } from "../../../common/ServeStatus"; | ||
import { ListItemCard } from "../../../components/ListItemCard"; | ||
import { useServeApplications } from "../../serve/hook/useServeApplications"; | ||
import { useServeDeployments } from "../../serve/hook/useServeApplications"; | ||
|
||
const useStyles = makeStyles((theme) => | ||
createStyles({ | ||
|
@@ -20,33 +20,45 @@ type RecentServeCardProps = { | |
export const RecentServeCard = ({ className }: RecentServeCardProps) => { | ||
const classes = useStyles(); | ||
|
||
// Use mock data by uncommenting the following line | ||
// const applications = mockServeApplications.applications; | ||
const { allServeApplications: applications } = useServeApplications(); | ||
const { allServeDeployments: deployments } = useServeDeployments(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we type some of the API response calls, such as it may be worth looking into at some point if we can automatically export typescript models based on ray There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's typed right here: https://github.com/ray-project/ray/blob/master/dashboard/client/src/type/serve.ts#L112 I do want to do generated types from the API but we don't have the infra for that yet right now. |
||
|
||
const sortedApplications = _.orderBy( | ||
applications, | ||
["last_deployed_time_s"], | ||
["desc"], | ||
const sortedDeployments = _.orderBy( | ||
deployments, | ||
["application.last_deployed_time_s", "name"], | ||
["desc", "asc"], | ||
).slice(0, 6); | ||
|
||
const sortedApplicationsToRender = sortedApplications.map((app) => { | ||
const sortedDeploymentsToRender = sortedDeployments.map((deployment) => { | ||
return { | ||
title: app.name, | ||
subtitle: app?.deployed_app_config?.import_path || "-", | ||
link: app.name ? `/serve/applications/${app.name}` : undefined, | ||
title: deployment.name, | ||
subtitle: | ||
deployment.application.deployed_app_config?.import_path || | ||
deployment.application.name || | ||
deployment.application.route_prefix, | ||
link: | ||
deployment.application.name && deployment.name | ||
? `/serve/applications/${encodeURIComponent( | ||
deployment.application.name, | ||
)}/${encodeURIComponent(deployment.name)}` | ||
: undefined, | ||
className: className, | ||
icon: <ServeStatusIcon className={classes.icon} app={app} small />, | ||
icon: ( | ||
<ServeStatusIcon | ||
className={classes.icon} | ||
deployment={deployment} | ||
small | ||
/> | ||
), | ||
}; | ||
}); | ||
|
||
return ( | ||
<ListItemCard | ||
headerTitle="Serve Applications" | ||
headerTitle="Serve Deployments" | ||
className={className} | ||
items={sortedApplicationsToRender} | ||
emptyListText="No Applications yet..." | ||
footerText="View all applications" | ||
items={sortedDeploymentsToRender} | ||
emptyListText="No Deployments yet..." | ||
footerText="View all deployments" | ||
footerLink="/serve" | ||
/> | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happened to applications? can they still be viewed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no application list page, but you can see the name of the application next to each deployment, and you can also use a filter to filter down to specific applications.
Someone can also still go to the application detail page by clicking into an application.
In general, people who use ray serve deal directly with deployments way more than applications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, maybe this should be in a release note on next ray release