Skip to content

Conversation

@mafredri
Copy link
Member

@mafredri mafredri commented Oct 23, 2025

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

Copy link
Member Author

mafredri commented Oct 23, 2025

@mafredri mafredri force-pushed the refactor-site-use-new-tasks-data-model-and-endpoints branch from 5f883dd to 1e0548c Compare October 23, 2025 08:32
@mafredri mafredri changed the base branch from mafredri/refactor-coderd-use-tasks-data-model-in-list to graphite-base/20431 October 23, 2025 08:37
@mafredri mafredri force-pushed the refactor-site-use-new-tasks-data-model-and-endpoints branch from eea8ed5 to 6d13866 Compare October 23, 2025 15:34
@mafredri mafredri force-pushed the graphite-base/20431 branch from 5fc4328 to 17fddfa Compare October 23, 2025 15:34
@mafredri mafredri changed the base branch from graphite-base/20431 to mafredri/chore-codersdk-document-taskstatus-and-taskstate October 23, 2025 15:35
@mafredri mafredri marked this pull request as ready for review October 23, 2025 15:51
@mafredri mafredri force-pushed the mafredri/chore-codersdk-document-taskstatus-and-taskstate branch 3 times, most recently from e1f7b87 to 0554fd1 Compare October 23, 2025 16:32
@mafredri mafredri force-pushed the refactor-site-use-new-tasks-data-model-and-endpoints branch from bd91d75 to d530c4d Compare October 23, 2025 16:41
@mafredri mafredri changed the base branch from mafredri/chore-codersdk-document-taskstatus-and-taskstate to mafredri/refactor-coderd-use-tasks-data-model-in-list October 23, 2025 16:44
@mafredri mafredri force-pushed the refactor-site-use-new-tasks-data-model-and-endpoints branch from d530c4d to c9f1efd Compare October 23, 2025 16:46
@mafredri mafredri force-pushed the mafredri/refactor-coderd-use-tasks-data-model-in-list branch 3 times, most recently from 9220413 to e605686 Compare October 23, 2025 17:11
Base automatically changed from mafredri/refactor-coderd-use-tasks-data-model-in-list to main October 23, 2025 17:22
@mafredri mafredri force-pushed the refactor-site-use-new-tasks-data-model-and-endpoints branch from c9f1efd to aecddaf Compare October 23, 2025 17:23
@BrunoQuaresma BrunoQuaresma requested a review from a team October 23, 2025 18:48
Copy link
Contributor

@buenos-nachos buenos-nachos left a 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

getTasks = async (
filter: TypesGen.TasksFilter,
): Promise<readonly TypesGen.Task[]> => {
const query = [];
Copy link
Contributor

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[]?

Comment on lines 28 to 30
export type WorkspaceAppWithAgent = WorkspaceApp & {
agent: WorkspaceAgent;
};
Copy link
Contributor

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

Copy link
Contributor

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

Comment on lines 155 to 162
return workspace.latest_build.resources
.flatMap((r) => r.agents ?? [])
.flatMap((agent) =>
agent.apps.map((app) => ({
...app,
agent,
})),
);
Copy link
Contributor

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

Copy link
Member

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.

Copy link
Contributor

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.

Comment on lines +203 to 205
const filter: TypesGen.TasksFilter = {
owner: user.username,
};
Copy link
Contributor

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

Copy link
Contributor

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 🤔

Comment on lines 22 to 25
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,
Copy link
Contributor

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:

  1. Split off the first mock task into a separate variable
  2. Put the variable in the array at the first position still
  3. 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)

Comment on lines +65 to +67
refetchInterval: ({ state }) => {
return state.error ? false : 5_000;
},
Copy link
Contributor

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

Copy link
Contributor

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.

Comment on lines +72 to +74
refetchInterval: ({ state }) => {
return state.error ? false : 5_000;
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question here

Comment on lines +202 to +203
queryKey: ["workspace", workspace.id, "parameters"],
queryFn: () => API.getWorkspaceParameters(workspace),
Copy link
Contributor

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

Copy link
Contributor

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.

Comment on lines -394 to -399
if (
workspace.latest_build.job.completed_at &&
!workspace.latest_build.has_ai_task
) {
throw new WorkspaceDoesNotHaveAITaskError(workspace);
}
Copy link
Contributor

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?

Copy link
Member

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.

Comment on lines 116 to 118
current_state: {
...(firstTask.current_state as TaskStateEntry),
state: "idle",
Copy link
Contributor

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?

Copy link
Member

@johnstcn johnstcn left a 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"`
Copy link
Member

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}.

Copy link
Member Author

@mafredri mafredri left a 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).
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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.

@BrunoQuaresma BrunoQuaresma merged commit 51d3abb into main Oct 24, 2025
31 checks passed
@BrunoQuaresma BrunoQuaresma deleted the refactor-site-use-new-tasks-data-model-and-endpoints branch October 24, 2025 13:45
@github-actions github-actions bot locked and limited conversation to collaborators Oct 24, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: tasks: refactor existing API endpoints to use new data model

5 participants