mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: redirect to the task page after creation (#18626)
Close https://github.com/coder/coder/issues/18184
This commit is contained in:
@@ -2,6 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { expect, spyOn, userEvent, waitFor, within } from "@storybook/test";
|
||||
import { API } from "api/api";
|
||||
import { MockUsers } from "pages/UsersPage/storybookData/users";
|
||||
import { reactRouterParameters } from "storybook-addon-remix-react-router";
|
||||
import {
|
||||
MockTemplate,
|
||||
MockTemplateVersionExternalAuthGithub,
|
||||
@@ -132,6 +133,23 @@ const newTaskData = {
|
||||
|
||||
export const CreateTaskSuccessfully: Story = {
|
||||
decorators: [withProxyProvider()],
|
||||
parameters: {
|
||||
reactRouter: reactRouterParameters({
|
||||
location: {
|
||||
path: "/tasks",
|
||||
},
|
||||
routing: [
|
||||
{
|
||||
path: "/tasks",
|
||||
useStoryElement: true,
|
||||
},
|
||||
{
|
||||
path: "/tasks/:ownerName/:workspaceName",
|
||||
element: <h1>Task page</h1>,
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
beforeEach: () => {
|
||||
spyOn(data, "fetchAITemplates").mockResolvedValue([MockTemplate]);
|
||||
spyOn(data, "fetchTasks")
|
||||
@@ -150,10 +168,8 @@ export const CreateTaskSuccessfully: Story = {
|
||||
await userEvent.click(submitButton);
|
||||
});
|
||||
|
||||
await step("Verify task in the table", async () => {
|
||||
await canvas.findByRole("row", {
|
||||
name: new RegExp(newTaskData.prompt, "i"),
|
||||
});
|
||||
await step("Redirects to the task page", async () => {
|
||||
await canvas.findByText(/task page/i);
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -187,7 +203,7 @@ export const CreateTaskError: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const WithExternalAuth: Story = {
|
||||
export const WithAuthenticatedExternalAuth: Story = {
|
||||
decorators: [withProxyProvider()],
|
||||
beforeEach: () => {
|
||||
spyOn(data, "fetchTasks")
|
||||
@@ -201,26 +217,17 @@ export const WithExternalAuth: Story = {
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await step("Run task", async () => {
|
||||
const prompt = await canvas.findByLabelText(/prompt/i);
|
||||
await userEvent.type(prompt, newTaskData.prompt);
|
||||
const submitButton = canvas.getByRole("button", { name: /run task/i });
|
||||
await waitFor(() => expect(submitButton).toBeEnabled());
|
||||
await userEvent.click(submitButton);
|
||||
});
|
||||
|
||||
await step("Verify task in the table", async () => {
|
||||
await canvas.findByRole("row", {
|
||||
name: new RegExp(newTaskData.prompt, "i"),
|
||||
});
|
||||
});
|
||||
|
||||
await step("Does not render external auth", async () => {
|
||||
expect(
|
||||
canvas.queryByText(/external authentication/),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
},
|
||||
parameters: {
|
||||
chromatic: {
|
||||
disableSnapshot: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const MissingExternalAuth: Story = {
|
||||
|
||||
@@ -52,7 +52,7 @@ import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName"
|
||||
import { type FC, type ReactNode, useState } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { Link as RouterLink, useNavigate } from "react-router-dom";
|
||||
import TextareaAutosize from "react-textarea-autosize";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { relativeTime } from "utils/time";
|
||||
@@ -163,6 +163,7 @@ const TaskFormSection: FC<{
|
||||
filter: TasksFilter;
|
||||
onFilterChange: (filter: TasksFilter) => void;
|
||||
}> = ({ showFilter, filter, onFilterChange }) => {
|
||||
const navigate = useNavigate();
|
||||
const {
|
||||
data: templates,
|
||||
error,
|
||||
@@ -190,7 +191,14 @@ const TaskFormSection: FC<{
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<TaskForm templates={templates} />
|
||||
<TaskForm
|
||||
templates={templates}
|
||||
onSuccess={(task) => {
|
||||
navigate(
|
||||
`/tasks/${task.workspace.owner_name}/${task.workspace.name}`,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{showFilter && (
|
||||
<TasksFilter filter={filter} onFilterChange={onFilterChange} />
|
||||
)}
|
||||
@@ -202,9 +210,10 @@ type CreateTaskMutationFnProps = { prompt: string; templateId: string };
|
||||
|
||||
type TaskFormProps = {
|
||||
templates: Template[];
|
||||
onSuccess: (task: Task) => void;
|
||||
};
|
||||
|
||||
const TaskForm: FC<TaskFormProps> = ({ templates }) => {
|
||||
const TaskForm: FC<TaskFormProps> = ({ templates, onSuccess }) => {
|
||||
const { user } = useAuthenticated();
|
||||
const queryClient = useQueryClient();
|
||||
const [selectedTemplateId, setSelectedTemplateId] = useState<string>(
|
||||
@@ -229,10 +238,11 @@ const TaskForm: FC<TaskFormProps> = ({ templates }) => {
|
||||
const createTaskMutation = useMutation({
|
||||
mutationFn: async ({ prompt, templateId }: CreateTaskMutationFnProps) =>
|
||||
data.createTask(prompt, user.id, templateId),
|
||||
onSuccess: async () => {
|
||||
onSuccess: async (task) => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["tasks"],
|
||||
});
|
||||
onSuccess(task);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -249,7 +259,6 @@ const TaskForm: FC<TaskFormProps> = ({ templates }) => {
|
||||
prompt,
|
||||
templateId: templateID,
|
||||
});
|
||||
form.reset();
|
||||
} catch (error) {
|
||||
const message = getErrorMessage(error, "Error creating task");
|
||||
const detail = getErrorDetail(error) ?? "Please try again";
|
||||
|
||||
Reference in New Issue
Block a user