- 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
Showing the changes to plugins/openapi (1 of 46 files). Show all
Unified · Split
| @@ -13,8 +13,14 @@ import { · 12 unmodified lines | |||
| 13 | useWorkspaceRequestContext, | 13 | useWorkspaceRequestContext, |
| 14 | } from "@executor/react"; | 14 | } from "@executor/react"; |
| 15 | import { | 15 | import { |
| 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 | <input | 395 | <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 | <input | 407 | <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 | <input | 420 | <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 | <select | 433 | <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 | <SecretReferenceField | 445 | <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 | <input | 457 | <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 | <input | 467 | <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 | <button | 482 | <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} operations | 494 | {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 | <button | 541 | <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 | <button | 784 | <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 | <button | 795 | <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 | Edit | 802 | 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 | <button | 809 | <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 | Cancel | 816 | Cancel |
| 811 | </button> | 817 | </Button> |
| 812 | <button | 818 | <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 | <button | 837 | <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 | Delete | 844 | Delete |
| 837 | </button> | 845 | </Button> |
| 838 | )} | 846 | )} |
| 839 | </> | 847 | </> |
| 840 | )} | 848 | )} |