History

Add shadcn UI components, fix Tailwind monorepo scanning, improve secret selector UX

- Add shadcn/ui component library (button, card, input, popover, command, dialog, etc.) - Fix Tailwind CSS not scanning workspace packages by adding correct @source directives in globals.css (root cause: paths needed ../../../ not ../../ from apps/web/src/) - Improve secret selector: replace trigger button + separate search with single search input that expands into results on focus - Update auth sections across plugins to use rounded bordered containers

Rhys Sullivan committed 7 months ago

Commit 05b2c841 parent 3fea5fb46 files · +1905 −792Browse files

Showing the changes to plugins/openapi (1 of 46 files). Show all

Unified · Split

plugins/openapi/react/components.tsx+69−61
@@ -13,8 +13,14 @@ import { · 12 unmodified lines
13 useWorkspaceRequestContext,13 useWorkspaceRequestContext,
14} from "@executor/react";14} from "@executor/react";
15import {15import {
16 Alert,
17 Button,
18 Card,
16 DocumentPanel,19 DocumentPanel,
17 IconPencil,20 IconPencil,
21 Input,
22 Label,
23 Select,
18 SourceToolDetailPanel,24 SourceToolDetailPanel,
19 SourceToolExplorer,25 SourceToolExplorer,
20 parseSourceToolExplorerSearch,26 parseSourceToolExplorerSearch,
@@ -381,63 +387,61 @@ function OpenApiSourceForm(props: { · 360 unmodified lines
381 };387 };
382 388
383 return (389 return (
384 <div className="space-y-6 rounded-xl border border-border p-6">390 <Card className="space-y-6 p-6">
385 <Section title="Connection">391 <Section title="Connection">
386 <div className="grid gap-4">392 <div className="grid gap-4">
387 <label className="grid gap-2">393 <div className="grid gap-2">
388 <span className="text-xs font-medium text-foreground">Name</span>394 <Label>Name</Label>
389 <input395 <Input
390 value={name}396 value={name}
391 onChange={(event) => {397 onChange={(event) => {
392 setNameEdited(true);398 setNameEdited(true);
393 setName(event.target.value);399 setName(event.target.value);
394 }}400 }}
395 placeholder="GitHub REST"401 placeholder="GitHub REST"
396 className="h-9 w-full rounded-lg border border-input bg-background px-3 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground/40 focus:border-ring focus:ring-1 focus:ring-ring/25"
397 />402 />
398 </label>403 </div>
399 404
400 <label className="grid gap-2">405 <div className="grid gap-2">
401 <span className="text-xs font-medium text-foreground">Spec URL</span>406 <Label>Spec URL</Label>
402 <input407 <Input
403 value={specUrl}408 value={specUrl}
404 onChange={(event) => setSpecUrl(event.target.value)}409 onChange={(event) => setSpecUrl(event.target.value)}
405 onBlur={() => {410 onBlur={() => {
406 void runPreview({ mode: "manual" });411 void runPreview({ mode: "manual" });
407 }}412 }}
408 placeholder="https://example.com/openapi.json"413 placeholder="https://example.com/openapi.json"
409 className="h-9 w-full rounded-lg border border-input bg-background px-3 font-mono text-xs text-foreground outline-none transition-colors placeholder:text-muted-foreground/40 focus:border-ring focus:ring-1 focus:ring-ring/25"414 className="font-mono text-xs"
410 />415 />
411 </label>416 </div>
412 417
413 <label className="grid gap-2">418 <div className="grid gap-2">
414 <span className="text-xs font-medium text-foreground">Base URL</span>419 <Label>Base URL</Label>
415 <input420 <Input
416 value={baseUrl}421 value={baseUrl}
417 onChange={(event) => {422 onChange={(event) => {
418 setBaseUrlEdited(true);423 setBaseUrlEdited(true);
419 setBaseUrl(event.target.value);424 setBaseUrl(event.target.value);
420 }}425 }}
421 placeholder="https://api.example.com"426 placeholder="https://api.example.com"
422 className="h-9 w-full rounded-lg border border-input bg-background px-3 font-mono text-xs text-foreground outline-none transition-colors placeholder:text-muted-foreground/40 focus:border-ring focus:ring-1 focus:ring-ring/25"427 className="font-mono text-xs"
423 />428 />
424 </label>429 </div>
425 430
426 <label className="grid gap-2">431 <div className="grid gap-2">
427 <span className="text-xs font-medium text-foreground">Auth</span>432 <Label>Auth</Label>
428 <select433 <Select
429 value={authKind}434 value={authKind}
430 onChange={(event) =>435 onChange={(event) =>
431 setAuthKind(event.target.value as OpenApiConnectInput["auth"]["kind"])}436 setAuthKind(event.target.value as OpenApiConnectInput["auth"]["kind"])}
432 className="h-9 w-full rounded-lg border border-input bg-background px-3 text-sm text-foreground outline-none transition-colors focus:border-ring focus:ring-1 focus:ring-ring/25"
433 >437 >
434 <option value="none">None</option>438 <option value="none">None</option>
435 <option value="bearer">Bearer Secret</option>439 <option value="bearer">Bearer Secret</option>
436 </select>440 </Select>
437 </label>441 </div>
438 442
439 {authKind === "bearer" && (443 {authKind === "bearer" && (
440 <div className="space-y-4 border-l-2 border-border pl-4">444 <div className="space-y-4 rounded-lg border border-border bg-muted/20 p-4">
441 <SecretReferenceField445 <SecretReferenceField
442 label="Secret"446 label="Secret"
443 value={tokenSecretRef}447 value={tokenSecretRef}
@@ -448,25 +452,25 @@ function OpenApiSourceForm(props: { · 4 unmodified lines
448 />452 />
449 453
450 <div className="grid gap-4 sm:grid-cols-2">454 <div className="grid gap-4 sm:grid-cols-2">
451 <label className="grid gap-2">455 <div className="grid gap-2">
452 <span className="text-xs font-medium text-foreground">Header Name</span>456 <Label>Header Name</Label>
453 <input457 <Input
454 value={authHeaderName}458 value={authHeaderName}
455 onChange={(event) => setAuthHeaderName(event.target.value)}459 onChange={(event) => setAuthHeaderName(event.target.value)}
456 placeholder={DEFAULT_BEARER_HEADER_NAME}460 placeholder={DEFAULT_BEARER_HEADER_NAME}
457 className="h-9 w-full rounded-lg border border-input bg-background px-3 font-mono text-xs text-foreground outline-none transition-colors placeholder:text-muted-foreground/40 focus:border-ring focus:ring-1 focus:ring-ring/25"461 className="font-mono text-xs"
458 />462 />
459 </label>463 </div>
460 464
461 <label className="grid gap-2">465 <div className="grid gap-2">
462 <span className="text-xs font-medium text-foreground">Prefix</span>466 <Label>Prefix</Label>
463 <input467 <Input
464 value={authPrefix}468 value={authPrefix}
465 onChange={(event) => setAuthPrefix(event.target.value)}469 onChange={(event) => setAuthPrefix(event.target.value)}
466 placeholder={DEFAULT_BEARER_PREFIX}470 placeholder={DEFAULT_BEARER_PREFIX}
467 className="h-9 w-full rounded-lg border border-input bg-background px-3 font-mono text-xs text-foreground outline-none transition-colors placeholder:text-muted-foreground/40 focus:border-ring focus:ring-1 focus:ring-ring/25"471 className="font-mono text-xs"
468 />472 />
469 </label>473 </div>
470 </div>474 </div>
471 </div>475 </div>
472 )}476 )}
@@ -475,16 +479,16 @@ function OpenApiSourceForm(props: { · 2 unmodified lines
475 479
476 <Section title="Preview">480 <Section title="Preview">
477 <div className="flex items-center gap-3">481 <div className="flex items-center gap-3">
478 <button482 <Button
483 variant="outline"
479 type="button"484 type="button"
480 onClick={() => {485 onClick={() => {
481 void runPreview({ mode: "manual" });486 void runPreview({ mode: "manual" });
482 }}487 }}
483 disabled={previewMutation.status === "pending" || submitMutation.status === "pending"}488 disabled={previewMutation.status === "pending" || submitMutation.status === "pending"}
484 className="inline-flex h-9 items-center justify-center rounded-lg border border-input bg-card px-3 text-sm font-medium text-foreground transition-colors hover:bg-accent/50 disabled:pointer-events-none disabled:opacity-50"
485 >489 >
486 {previewMutation.status === "pending" ? "Previewing..." : "Preview Spec"}490 {previewMutation.status === "pending" ? "Previewing..." : "Preview Spec"}
487 </button>491 </Button>
488 {preview && (492 {preview && (
489 <div className="text-xs text-muted-foreground">493 <div className="text-xs text-muted-foreground">
490 {preview.operationCount} operations494 {preview.operationCount} operations
@@ -519,33 +523,32 @@ function OpenApiSourceForm(props: { · 28 unmodified lines
519 )}523 )}
520 </dl>524 </dl>
521 {preview.warnings.length > 0 && (525 {preview.warnings.length > 0 && (
522 <div className="mt-3 rounded-md border border-amber-300/40 bg-amber-100/20 px-3 py-2 text-xs text-amber-800">526 <Alert variant="warning" className="mt-3 text-xs">
523 {preview.warnings.join(" ")}527 {preview.warnings.join(" ")}
524 </div>528 </Alert>
525 )}529 )}
526 </div>530 </div>
527 )}531 )}
528 </Section>532 </Section>
529 533
530 {error && (534 {error && (
531 <div className="rounded-lg border border-destructive/30 bg-destructive/8 px-4 py-2.5 text-sm text-destructive">535 <Alert variant="destructive">
532 {error}536 {error}
533 </div>537 </Alert>
534 )}538 )}
535 539
536 <div className="flex items-center justify-end">540 <div className="flex items-center justify-end">
537 <button541 <Button
538 type="button"542 type="button"
539 onClick={() => {543 onClick={() => {
540 void handleSubmit();544 void handleSubmit();
541 }}545 }}
542 disabled={submitMutation.status === "pending"}546 disabled={submitMutation.status === "pending"}
543 className="inline-flex h-9 items-center justify-center rounded-lg bg-primary px-4 text-sm font-medium text-primary-foreground transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-50"
544 >547 >
545 {submitMutation.status === "pending" ? props.busyLabel : props.submitLabel}548 {submitMutation.status === "pending" ? props.busyLabel : props.submitLabel}
546 </button>549 </Button>
547 </div>550 </div>
548 </div>551 </Card>
549 );552 );
550}553}
551 554
@@ -641,9 +644,9 @@ function OpenApiEditSourcePageReady(props: { · 89 unmodified lines
641 if (Result.isFailure(configResult)) {644 if (Result.isFailure(configResult)) {
642 return (645 return (
643 <Section title="Edit Source">646 <Section title="Edit Source">
644 <div className="rounded-lg border border-destructive/30 bg-destructive/8 p-4 text-sm text-destructive">647 <Alert variant="destructive">
645 Failed loading source configuration.648 Failed loading source configuration.
646 </div>649 </Alert>
647 </Section>650 </Section>
648 );651 );
649 }652 }
@@ -778,38 +781,43 @@ function OpenApiSourceDetailPageReady(props: { · 128 unmodified lines
778 })}781 })}
779 actions={(782 actions={(
780 <>783 <>
781 <button784 <Button
785 variant="outline"
786 size="sm"
782 type="button"787 type="button"
783 onClick={() => {788 onClick={() => {
784 void refreshMutation.mutateAsync(props.source.id);789 void refreshMutation.mutateAsync(props.source.id);
785 }}790 }}
786 disabled={refreshMutation.status === "pending"}791 disabled={refreshMutation.status === "pending"}
787 className="inline-flex items-center gap-1.5 rounded-md border border-border bg-card px-2.5 py-1 text-[12px] font-medium text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground disabled:pointer-events-none disabled:opacity-50"
788 >792 >
789 {refreshMutation.status === "pending" ? "Refreshing..." : "Refresh"}793 {refreshMutation.status === "pending" ? "Refreshing..." : "Refresh"}
790 </button>794 </Button>
791 <button795 <Button
796 variant="outline"
797 size="sm"
792 type="button"798 type="button"
793 onClick={() => void navigation.edit(props.source.id)}799 onClick={() => void navigation.edit(props.source.id)}
794 className="inline-flex items-center gap-1.5 rounded-md border border-border bg-card px-2.5 py-1 text-[12px] font-medium text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
795 >800 >
796 <IconPencil className="size-3" />801 <IconPencil className="size-3" />
797 Edit802 Edit
798 </button>803 </Button>
799 {confirmDelete ? (804 {confirmDelete ? (
800 <div className="flex items-center gap-2">805 <div className="flex items-center gap-2">
801 <span className="text-[11px] font-medium text-destructive">806 <span className="text-[11px] font-medium text-destructive">
802 Confirm delete?807 Confirm delete?
803 </span>808 </span>
804 <button809 <Button
810 variant="outline"
811 size="sm"
805 type="button"812 type="button"
806 onClick={() => setConfirmDelete(false)}813 onClick={() => setConfirmDelete(false)}
807 disabled={removeMutation.status === "pending"}814 disabled={removeMutation.status === "pending"}
808 className="inline-flex items-center rounded-md border border-border bg-card px-2.5 py-1 text-[12px] font-medium text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground disabled:pointer-events-none disabled:opacity-50"
809 >815 >
810 Cancel816 Cancel
811 </button>817 </Button>
812 <button818 <Button
819 variant="destructive-outline"
820 size="sm"
813 type="button"821 type="button"
814 onClick={() => {822 onClick={() => {
815 void removeMutation.mutateAsync(props.source.id).then(() => {823 void removeMutation.mutateAsync(props.source.id).then(() => {
@@ -821,20 +829,20 @@ function OpenApiSourceDetailPageReady(props: { · 5 unmodified lines
821 });829 });
822 }}830 }}
823 disabled={removeMutation.status === "pending"}831 disabled={removeMutation.status === "pending"}
824 className="inline-flex items-center rounded-md border border-destructive/25 bg-destructive/5 px-2.5 py-1 text-[12px] font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:pointer-events-none disabled:opacity-50"
825 >832 >
826 {removeMutation.status === "pending" ? "Deleting..." : "Delete"}833 {removeMutation.status === "pending" ? "Deleting..." : "Delete"}
827 </button>834 </Button>
828 </div>835 </div>
829 ) : (836 ) : (
830 <button837 <Button
838 variant="destructive-outline"
839 size="sm"
831 type="button"840 type="button"
832 onClick={() => setConfirmDelete(true)}841 onClick={() => setConfirmDelete(true)}
833 disabled={removeMutation.status === "pending"}842 disabled={removeMutation.status === "pending"}
834 className="inline-flex items-center rounded-md border border-destructive/25 bg-destructive/5 px-2.5 py-1 text-[12px] font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:pointer-events-none disabled:opacity-50"
835 >843 >
836 Delete844 Delete
837 </button>845 </Button>
838 )}846 )}
839 </>847 </>
840 )}848 )}