Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit da84dd6

Browse files
committed
refactor: move required external auth buttons to the submit side
1 parent 6c713d5 commit da84dd6

File tree

1 file changed

+74
-56
lines changed

1 file changed

+74
-56
lines changed

site/src/pages/TasksPage/TasksPage.tsx

Lines changed: 74 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ import Skeleton from "@mui/material/Skeleton";
22
import { API } from "api/api";
33
import { getErrorDetail, getErrorMessage } from "api/errors";
44
import { disabledRefetchOptions } from "api/queries/util";
5-
import type { Template } from "api/typesGenerated";
5+
import type { Template, TemplateVersionExternalAuth } from "api/typesGenerated";
66
import { ErrorAlert } from "components/Alert/ErrorAlert";
77
import { Avatar } from "components/Avatar/Avatar";
88
import { AvatarData } from "components/Avatar/AvatarData";
99
import { AvatarDataSkeleton } from "components/Avatar/AvatarDataSkeleton";
1010
import { Button } from "components/Button/Button";
11-
import { Form, FormFields, FormSection } from "components/Form/Form";
1211
import { displayError } from "components/GlobalSnackbar/utils";
1312
import { Margins } from "components/Margins/Margins";
1413
import {
@@ -39,7 +38,7 @@ import {
3938

4039
import { useAuthenticated } from "hooks";
4140
import { useExternalAuth } from "hooks/useExternalAuth";
42-
import { RotateCcwIcon, SendIcon } from "lucide-react";
41+
import { AlertTriangleIcon, RotateCcwIcon, SendIcon } from "lucide-react";
4342
import { AI_PROMPT_PARAMETER_NAME, type Task } from "modules/tasks/tasks";
4443
import { WorkspaceAppStatus } from "modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus";
4544
import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName";
@@ -52,10 +51,12 @@ import { pageTitle } from "utils/page";
5251
import { relativeTime } from "utils/time";
5352
import { ExternalAuthButton } from "../CreateWorkspacePage/ExternalAuthButton";
5453
import { type UserOption, UsersCombobox } from "./UsersCombobox";
54+
import { ExternalImage } from "components/ExternalImage/ExternalImage";
5555

5656
type TasksFilter = {
5757
user: UserOption | undefined;
5858
};
59+
5960
const TasksPage: FC = () => {
6061
const { user, permissions } = useAuthenticated();
6162
const [filter, setFilter] = useState<TasksFilter>({
@@ -201,21 +202,20 @@ type TaskFormProps = {
201202
const TaskForm: FC<TaskFormProps> = ({ templates }) => {
202203
const { user } = useAuthenticated();
203204
const queryClient = useQueryClient();
204-
205-
const [templateId, setTemplateId] = useState<string>(templates[0].id);
206-
const {
207-
externalAuth,
208-
externalAuthPollingState,
209-
startPollingExternalAuth,
210-
isLoadingExternalAuth,
211-
externalAuthError,
212-
} = useExternalAuth(
213-
templates.find((t) => t.id === templateId)?.active_version_id,
205+
const [selectedTemplateId, setSelectedTemplateId] = useState<string>(
206+
templates[0].id,
214207
);
215-
216-
const hasAllRequiredExternalAuth = externalAuth?.every(
217-
(auth) => auth.optional || auth.authenticated,
208+
const selectedTemplate = templates.find(
209+
(t) => t.id === selectedTemplateId,
210+
) as Template;
211+
const { externalAuth, isLoadingExternalAuth, externalAuthError } =
212+
useExternalAuth(selectedTemplate.active_version_id);
213+
const missedExternalAuth = externalAuth?.filter(
214+
(auth) => !auth.optional && !auth.authenticated,
218215
);
216+
const isMissingExternalAuth = missedExternalAuth
217+
? missedExternalAuth.length > 0
218+
: true;
219219

220220
const createTaskMutation = useMutation({
221221
mutationFn: async ({ prompt, templateId }: CreateTaskMutationFnProps) =>
@@ -235,10 +235,6 @@ const TaskForm: FC<TaskFormProps> = ({ templates }) => {
235235
const prompt = formData.get("prompt") as string;
236236
const templateID = formData.get("templateID") as string;
237237

238-
if (!prompt || !templateID) {
239-
return;
240-
}
241-
242238
try {
243239
await createTaskMutation.mutateAsync({
244240
prompt,
@@ -253,8 +249,12 @@ const TaskForm: FC<TaskFormProps> = ({ templates }) => {
253249
};
254250

255251
return (
256-
<Form onSubmit={onSubmit} aria-label="Create AI task">
257-
{Boolean(externalAuthError) && <ErrorAlert error={externalAuthError} />}
252+
<form
253+
onSubmit={onSubmit}
254+
aria-label="Create AI task"
255+
className="flex flex-col gap-4"
256+
>
257+
{externalAuthError && <ErrorAlert error={externalAuthError} />}
258258

259259
<fieldset
260260
className="border border-border border-solid rounded-lg p-4"
@@ -274,7 +274,7 @@ const TaskForm: FC<TaskFormProps> = ({ templates }) => {
274274
<div className="flex items-center justify-between pt-2">
275275
<Select
276276
name="templateID"
277-
onValueChange={(value) => setTemplateId(value)}
277+
onValueChange={(value) => setSelectedTemplateId(value)}
278278
defaultValue={templates[0].id}
279279
required
280280
>
@@ -294,43 +294,61 @@ const TaskForm: FC<TaskFormProps> = ({ templates }) => {
294294
</SelectContent>
295295
</Select>
296296

297-
<Button
298-
size="sm"
299-
type="submit"
300-
disabled={!hasAllRequiredExternalAuth}
301-
>
302-
<Spinner
303-
loading={createTaskMutation.isPending || isLoadingExternalAuth}
304-
>
305-
<SendIcon />
306-
</Spinner>
307-
Run task
308-
</Button>
297+
<div className="flex items-center gap-2">
298+
{missedExternalAuth && isMissingExternalAuth && (
299+
<ExternalAuthButtons
300+
template={selectedTemplate}
301+
missedExternalAuth={missedExternalAuth}
302+
/>
303+
)}
304+
305+
<Button size="sm" type="submit" disabled={isMissingExternalAuth}>
306+
<Spinner
307+
loading={createTaskMutation.isPending || isLoadingExternalAuth}
308+
>
309+
<SendIcon />
310+
</Spinner>
311+
Run task
312+
</Button>
313+
</div>
309314
</div>
310315
</fieldset>
316+
</form>
317+
);
318+
};
311319

312-
{!hasAllRequiredExternalAuth &&
313-
externalAuth &&
314-
externalAuth.length > 0 && (
315-
<FormSection
316-
title="External Authentication"
317-
description="This template uses external services for authentication."
318-
>
319-
<FormFields>
320-
{externalAuth.map((auth) => (
321-
<ExternalAuthButton
322-
key={auth.id}
323-
auth={auth}
324-
isLoading={externalAuthPollingState === "polling"}
325-
onStartPolling={startPollingExternalAuth}
326-
displayRetry={externalAuthPollingState === "abandoned"}
327-
/>
328-
))}
329-
</FormFields>
330-
</FormSection>
331-
)}
332-
</Form>
320+
type ExternalAuthButtonProps = {
321+
template: Template;
322+
missedExternalAuth: TemplateVersionExternalAuth[];
323+
};
324+
325+
const ExternalAuthButtons: FC<ExternalAuthButtonProps> = ({
326+
template,
327+
missedExternalAuth,
328+
}) => {
329+
const { startPollingExternalAuth, isLoadingExternalAuth } = useExternalAuth(
330+
template.active_version_id,
333331
);
332+
333+
return missedExternalAuth.map((auth) => {
334+
return (
335+
<Button
336+
variant="outline"
337+
key={auth.id}
338+
size="sm"
339+
disabled={isLoadingExternalAuth || auth.authenticated}
340+
onClick={() => {
341+
window.open(auth.authenticate_url, "_blank", "width=900,height=600");
342+
startPollingExternalAuth();
343+
}}
344+
>
345+
<Spinner loading={isLoadingExternalAuth}>
346+
<ExternalImage src={auth.display_icon} />
347+
</Spinner>
348+
Login with {auth.display_name}
349+
</Button>
350+
);
351+
});
334352
};
335353

336354
type TasksFilterProps = {

0 commit comments

Comments
 (0)