-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat(site): use new task data model and endpoints #20431
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
feat(site): use new task data model and endpoints #20431
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
5f883dd to
1e0548c
Compare
eea8ed5 to
6d13866
Compare
5fc4328 to
17fddfa
Compare
e1f7b87 to
0554fd1
Compare
bd91d75 to
d530c4d
Compare
d530c4d to
c9f1efd
Compare
9220413 to
e605686
Compare
c9f1efd to
aecddaf
Compare
buenos-nachos
left a comment
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.
Nothing major stuck out to me for the frontend changes, but I did have a few questions.
The main thing that stuck out to me was whether we can stop polling every five seconds for some of the tasks, or if that's something we absolutely need for UX
site/src/api/api.ts
Outdated
| getTasks = async ( | ||
| filter: TypesGen.TasksFilter, | ||
| ): Promise<readonly TypesGen.Task[]> => { | ||
| const query = []; |
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.
Nit: can we type this as string[]?
site/src/modules/apps/apps.ts
Outdated
| export type WorkspaceAppWithAgent = WorkspaceApp & { | ||
| agent: WorkspaceAgent; | ||
| }; |
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.
Nit: I know this is used in a few other files, but just because this is only used in one spot for this file, I'd move the type definition to be closer to where it's used, especially since it's more of a "kludge" type
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.
Moved to modules/tasks/apps.ts
site/src/modules/apps/apps.ts
Outdated
| return workspace.latest_build.resources | ||
| .flatMap((r) => r.agents ?? []) | ||
| .flatMap((agent) => | ||
| agent.apps.map((app) => ({ | ||
| ...app, | ||
| agent, | ||
| })), | ||
| ); |
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.
I wish I knew a little bit more of Coder's backend implementations so I didn't have to ask this: are the same apps able to be shared across multiple agents? I'm wondering if we need any de-duplication
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.
No, a workspace_app is linked to a single workspace_agent.
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.
Yes. We can change this function to accept an agent ID, but the agent ID can be null depending on the state. Unfortunately, sice Go does not support uninon types, we need to update the code in a few places to handle that. Since we are quite out of time for this, I'm going to skip it for now.
| const filter: TypesGen.TasksFilter = { | ||
| owner: user.username, | ||
| }; |
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.
We should be able to extract it outside of the component so it doesn't get recreated each render
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.
Not sure if I go it... the filter needs to be mounted inside of the component, so we can access the user.username 🤔
| path: `/tasks/${MockTasks[0].owner_name}/${MockTasks[0].id}`, | ||
| pathParams: { | ||
| workspace: MockTasks[0].workspace.name, | ||
| owner_name: MockTasks[0].owner_name, | ||
| task: MockTasks[0].id, |
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.
Not a huge deal, but I'm wondering if we can:
- Split off the first mock task into a separate variable
- Put the variable in the array at the first position still
- Export the variable along with the array
It's not a big deal for a story, but in production, I would want to make sure that when we're dealing with empty arrays properly (and our tsconfig file isn't tuned tightly enough to catch potential mismatches at the type level)
| refetchInterval: ({ state }) => { | ||
| return state.error ? false : 5_000; | ||
| }, |
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.
Do we want this to be constantly refetching? Because even if all tasks are settled, we'll still refetch every five seconds, as long as there is no error
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.
Yes, because task has statuses and states that are updated during its lifecycle.
| refetchInterval: ({ state }) => { | ||
| return state.error ? false : 5_000; | ||
| }, |
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.
Same question here
| queryKey: ["workspace", workspace.id, "parameters"], | ||
| queryFn: () => API.getWorkspaceParameters(workspace), |
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.
I feel like the API setup is a little bit off here. The API function only needs the workspace's latest build, but we're not putting it in the query key, and we're also putting in the workspace's ID, which isn't used by the function at all
Wondering if it might be worth changing what the API function accepts at input to minimize its dependencies
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.
I do agree with you, but we are doing this in three other places in the codebase, so I'm not going to touch this right now, since it would be outside of the scope.
| if ( | ||
| workspace.latest_build.job.completed_at && | ||
| !workspace.latest_build.has_ai_task | ||
| ) { | ||
| throw new WorkspaceDoesNotHaveAITaskError(workspace); | ||
| } |
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.
Do we need equivalent functionality still, or do we have guarantees that we'll never trigger it?
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.
We've inverted the relationship, there is now a tasks table with a workspace_id column.
| current_state: { | ||
| ...(firstTask.current_state as TaskStateEntry), | ||
| state: "idle", |
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.
Instead of doing the type assertion, could we pass a function to mockResolvedValue, and have it throw an error if firstTask.current_state is null?
johnstcn
left a comment
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.
Backend changes LGTM
| TemplateDisplayName string `json:"template_display_name" table:"template display name"` | ||
| TemplateIcon string `json:"template_icon" table:"template icon"` | ||
| WorkspaceID uuid.NullUUID `json:"workspace_id" format:"uuid" table:"workspace id"` | ||
| WorkspaceName string `json:"workspace_name" table:"workspace name"` |
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.
Might be good to add some asserts for this in coderd/aitasks_test.go e.g. in TestTasks/{Get,List}.
mafredri
left a comment
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.
BE changes look good 👍🏻
| FilterQuery string `json:"filter_query,omitempty"` | ||
| } | ||
|
|
||
| // Experimental response shape for tasks list (server returns []Task). |
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.
| // Experimental response shape for tasks list (server returns []Task). | |
| // TaskListResponse is the response shape for tasks list. | |
| // | |
| // Experimental: This type is experimental and may change in the future. |
…ite-use-new-tasks-data-model-and-endpoints

Updates the UI to use the new API endpoints for tasks and use its new data model.
Disclaimer: Since the base data model for tasks changed, we had to do a quite large refactor and I'm sorry for that 🙏, but you'll notice most of the changes are to adjust the types.
Closes coder/internal#976