When a transparent-DCR (or CIMD) OAuth integration also exposed a custom-method '+' (createCustomMethod), the method tab strip rendered but its TabsContent card was gated out by a 'dcrActive ? null' wrapper, leaving the tabs floating with no body and a detached-looking border. That same wrapper also made the in-card 'No app to choose' DCR explainer unreachable dead code. Always render TabsContent and let the inner dcrActive / cimdActive branches show the explainer, so the tab strip gets its card back.
Showing the changes to packages (1 of 1 file). Show all
Unified · Split
| @@ -1722,186 +1722,184 @@ function AddAccountModalView(props: AddAccountModalProps) { · 1721 unmodified lines | ||
| 1722 | 1722 | </div> |
| 1723 | 1723 | </TabsList> |
| 1724 | 1724 | |
| 1725 | − {dcrActive ? null : ( | |
| 1726 | − <TabsContent | |
| 1727 | − value={methodId} | |
| 1728 | − className={cn( | |
| 1729 | − "mt-0 min-w-0 space-y-5", | |
| 1730 | − // No-auth renders no fields, so skip the framed box that | |
| 1731 | − // would otherwise show up as an empty bordered panel. | |
| 1732 | − // Otherwise the panel attaches to the tab header above | |
| 1733 | − // (square top, rounded bottom). | |
| 1734 | − isNoAuth | |
| 1735 | − ? null | |
| 1736 | − : "rounded-b-md rounded-t-none border border-border/60 bg-muted/15 p-4", | |
| 1737 | − )} | |
| 1738 | − > | |
| 1739 | − {method?.placements && !isEnvMethod && singleInput && !singleCredentialAffix | |
| 1740 | − ? (() => { | |
| 1741 | − const shown = method.placements.filter((p) => p.carrier !== "env"); | |
| 1742 | − return shown.length > 0 ? ( | |
| 1743 | − <div className="flex flex-wrap gap-x-3.5 gap-y-1"> | |
| 1744 | − {shown.map((placement, i: number) => ( | |
| 1745 | − <PlacementLine key={i} placement={placement} /> | |
| 1746 | − ))} | |
| 1747 | − </div> | |
| 1748 | − ) : null; | |
| 1749 | − })() | |
| 1750 | − : null} | |
| 1751 | − | |
| 1752 | − {!isNoAuth && ( | |
| 1753 | − <div className="space-y-2"> | |
| 1754 | − <StepHeader index={2} label={authStepLabel} /> | |
| 1755 | − | |
| 1756 | − {isOAuth && method ? ( | |
| 1757 | − cimdActive ? ( | |
| 1758 | − <div className="space-y-2 rounded-lg border border-ring/40 bg-accent/30 px-3 py-3"> | |
| 1759 | − <p className="text-sm font-medium">No app registration</p> | |
| 1760 | − <p className="text-xs text-muted-foreground"> | |
| 1761 | − {cimdConnecting | |
| 1762 | − ? `Connecting to ${integrationName}…` | |
| 1763 | − : `${integrationName} supports Client ID Metadata Document OAuth. We'll use this Executor host's public client metadata document and sign you in.`} | |
| 1764 | − </p> | |
| 1765 | − </div> | |
| 1766 | − ) : dcrActive ? ( | |
| 1767 | − // Transparent DCR: no picker. We register an app for you and run | |
| 1768 | − // the OAuth flow with a single Connect click. | |
| 1769 | − <div className="space-y-2 rounded-lg border border-ring/40 bg-accent/30 px-3 py-3"> | |
| 1770 | − <p className="text-sm font-medium">No app to choose</p> | |
| 1771 | − <p className="text-xs text-muted-foreground"> | |
| 1772 | − {dcrConnecting | |
| 1773 | − ? `Connecting to ${integrationName}…` | |
| 1774 | − : `${integrationName} supports automatic setup. We register an app for you and sign you in — no client ID or app to pick.`} | |
| 1775 | − </p> | |
| 1776 | − </div> | |
| 1777 | − ) : oauthLoading ? ( | |
| 1778 | − <p className="text-xs text-muted-foreground">Loading OAuth apps…</p> | |
| 1779 | − ) : ( | |
| 1780 | − <div className="space-y-3"> | |
| 1781 | − {dcrFallbackMessage ? ( | |
| 1782 | − <div | |
| 1783 | − role="alert" | |
| 1784 | − className="space-y-1 rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-3" | |
| 1785 | − > | |
| 1786 | − <p className="text-sm font-medium text-destructive"> | |
| 1787 | − Couldn't set up {integrationName} automatically | |
| 1788 | − </p> | |
| 1789 | − <p className="text-xs text-muted-foreground"> | |
| 1790 | − {dcrFallbackMessage} | |
| 1791 | − </p> | |
| 1792 | − <p className="text-xs text-muted-foreground"> | |
| 1793 | − Register an app below to connect. | |
| 1794 | − </p> | |
| 1795 | − </div> | |
| 1796 | − ) : null} | |
| 1797 | − {/* No registered app matched the integration's endpoint: | |
| 1725 | + <TabsContent | |
| 1726 | + value={methodId} | |
| 1727 | + className={cn( | |
| 1728 | + "mt-0 min-w-0 space-y-5", | |
| 1729 | + // No-auth renders no fields, so skip the framed box that | |
| 1730 | + // would otherwise show up as an empty bordered panel. | |
| 1731 | + // Otherwise the panel attaches to the tab header above | |
| 1732 | + // (square top, rounded bottom). | |
| 1733 | + isNoAuth | |
| 1734 | + ? null | |
| 1735 | + : "rounded-b-md rounded-t-none border border-border/60 bg-muted/15 p-4", | |
| 1736 | + )} | |
| 1737 | + > | |
| 1738 | + {method?.placements && !isEnvMethod && singleInput && !singleCredentialAffix | |
| 1739 | + ? (() => { | |
| 1740 | + const shown = method.placements.filter((p) => p.carrier !== "env"); | |
| 1741 | + return shown.length > 0 ? ( | |
| 1742 | + <div className="flex flex-wrap gap-x-3.5 gap-y-1"> | |
| 1743 | + {shown.map((placement, i: number) => ( | |
| 1744 | + <PlacementLine key={i} placement={placement} /> | |
| 1745 | + ))} | |
| 1746 | + </div> | |
| 1747 | + ) : null; | |
| 1748 | + })() | |
| 1749 | + : null} | |
| 1750 | + | |
| 1751 | + {!isNoAuth && ( | |
| 1752 | + <div className="space-y-2"> | |
| 1753 | + <StepHeader index={2} label={authStepLabel} /> | |
| 1754 | + | |
| 1755 | + {isOAuth && method ? ( | |
| 1756 | + cimdActive ? ( | |
| 1757 | + <div className="space-y-2 rounded-lg border border-ring/40 bg-accent/30 px-3 py-3"> | |
| 1758 | + <p className="text-sm font-medium">No app registration</p> | |
| 1759 | + <p className="text-xs text-muted-foreground"> | |
| 1760 | + {cimdConnecting | |
| 1761 | + ? `Connecting to ${integrationName}…` | |
| 1762 | + : `${integrationName} supports Client ID Metadata Document OAuth. We'll use this Executor host's public client metadata document and sign you in.`} | |
| 1763 | + </p> | |
| 1764 | + </div> | |
| 1765 | + ) : dcrActive ? ( | |
| 1766 | + // Transparent DCR: no picker. We register an app for you and run | |
| 1767 | + // the OAuth flow with a single Connect click. | |
| 1768 | + <div className="space-y-2 rounded-lg border border-ring/40 bg-accent/30 px-3 py-3"> | |
| 1769 | + <p className="text-sm font-medium">No app to choose</p> | |
| 1770 | + <p className="text-xs text-muted-foreground"> | |
| 1771 | + {dcrConnecting | |
| 1772 | + ? `Connecting to ${integrationName}…` | |
| 1773 | + : `${integrationName} supports automatic setup. We register an app for you and sign you in — no client ID or app to pick.`} | |
| 1774 | + </p> | |
| 1775 | + </div> | |
| 1776 | + ) : oauthLoading ? ( | |
| 1777 | + <p className="text-xs text-muted-foreground">Loading OAuth apps…</p> | |
| 1778 | + ) : ( | |
| 1779 | + <div className="space-y-3"> | |
| 1780 | + {dcrFallbackMessage ? ( | |
| 1781 | + <div | |
| 1782 | + role="alert" | |
| 1783 | + className="space-y-1 rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-3" | |
| 1784 | + > | |
| 1785 | + <p className="text-sm font-medium text-destructive"> | |
| 1786 | + Couldn't set up {integrationName} automatically | |
| 1787 | + </p> | |
| 1788 | + <p className="text-xs text-muted-foreground"> | |
| 1789 | + {dcrFallbackMessage} | |
| 1790 | + </p> | |
| 1791 | + <p className="text-xs text-muted-foreground"> | |
| 1792 | + Register an app below to connect. | |
| 1793 | + </p> | |
| 1794 | + </div> | |
| 1795 | + ) : null} | |
| 1796 | + {/* No registered app matched the integration's endpoint: | |
| 1798 | 1797 | empty state + a prominent register CTA, and an opt-in |
| 1799 | 1798 | collapsed "use a different registered app" escape hatch. */} |
| 1800 | − {oauthDisplayRegisterCTA && ( | |
| 1801 | − <div className="space-y-3 rounded-lg border border-border/60 bg-muted/20 px-3 py-3"> | |
| 1802 | − <p className="text-sm font-medium"> | |
| 1803 | − No app for {integrationName} yet | |
| 1804 | − </p> | |
| 1805 | − <p className="text-xs text-muted-foreground"> | |
| 1806 | − None of your registered apps target this integration's OAuth | |
| 1807 | − endpoint. Register one to connect. | |
| 1808 | − </p> | |
| 1809 | − <div className="flex flex-wrap items-center gap-2 pt-1"> | |
| 1799 | + {oauthDisplayRegisterCTA && ( | |
| 1800 | + <div className="space-y-3 rounded-lg border border-border/60 bg-muted/20 px-3 py-3"> | |
| 1801 | + <p className="text-sm font-medium"> | |
| 1802 | + No app for {integrationName} yet | |
| 1803 | + </p> | |
| 1804 | + <p className="text-xs text-muted-foreground"> | |
| 1805 | + None of your registered apps target this integration's OAuth | |
| 1806 | + endpoint. Register one to connect. | |
| 1807 | + </p> | |
| 1808 | + <div className="flex flex-wrap items-center gap-2 pt-1"> | |
| 1809 | + <Button | |
| 1810 | + type="button" | |
| 1811 | + size="sm" | |
| 1812 | + onClick={() => setRegisteringOAuthClient(true)} | |
| 1813 | + > | |
| 1814 | + {dcrFallbackMessage | |
| 1815 | + ? "Manually register an app" | |
| 1816 | + : "Register app"} | |
| 1817 | + </Button> | |
| 1818 | + {oauthOtherApps.length > 0 && !showOtherApps ? ( | |
| 1810 | 1819 | <Button |
| 1811 | 1820 | type="button" |
| 1821 | + variant="outline" | |
| 1812 | 1822 | size="sm" |
| 1813 | − onClick={() => setRegisteringOAuthClient(true)} | |
| 1823 | + onClick={() => setShowOtherApps(true)} | |
| 1814 | 1824 | > |
| 1815 | − {dcrFallbackMessage | |
| 1816 | − ? "Manually register an app" | |
| 1817 | − : "Register app"} | |
| 1825 | + Use another app | |
| 1818 | 1826 | </Button> |
| 1819 | − {oauthOtherApps.length > 0 && !showOtherApps ? ( | |
| 1820 | − <Button | |
| 1821 | − type="button" | |
| 1822 | − variant="outline" | |
| 1823 | − size="sm" | |
| 1824 | − onClick={() => setShowOtherApps(true)} | |
| 1825 | − > | |
| 1826 | − Use another app | |
| 1827 | − </Button> | |
| 1828 | − ) : null} | |
| 1829 | − </div> | |
| 1830 | − {oauthOtherApps.length > 0 && showOtherApps ? ( | |
| 1831 | − <RadioGroup | |
| 1832 | − value={selectedApp} | |
| 1833 | − onValueChange={setPickedApp} | |
| 1834 | − className="gap-2 pt-1" | |
| 1835 | − > | |
| 1836 | − {oauthOtherApps.map((app: OAuthClientOption) => ( | |
| 1837 | − <OAuthAppRadioRow | |
| 1838 | − key={String(app.slug)} | |
| 1839 | − app={app} | |
| 1840 | − idPrefix="other-app" | |
| 1841 | − variant="other" | |
| 1842 | − showOwnerLabel={ownerDisplay.showOwnerLabels} | |
| 1843 | − onManage={manageHandlersFor(app)} | |
| 1844 | − /> | |
| 1845 | − ))} | |
| 1846 | − </RadioGroup> | |
| 1847 | 1827 | ) : null} |
| 1848 | 1828 | </div> |
| 1849 | − )} | |
| 1829 | + {oauthOtherApps.length > 0 && showOtherApps ? ( | |
| 1830 | + <RadioGroup | |
| 1831 | + value={selectedApp} | |
| 1832 | + onValueChange={setPickedApp} | |
| 1833 | + className="gap-2 pt-1" | |
| 1834 | + > | |
| 1835 | + {oauthOtherApps.map((app: OAuthClientOption) => ( | |
| 1836 | + <OAuthAppRadioRow | |
| 1837 | + key={String(app.slug)} | |
| 1838 | + app={app} | |
| 1839 | + idPrefix="other-app" | |
| 1840 | + variant="other" | |
| 1841 | + showOwnerLabel={ownerDisplay.showOwnerLabels} | |
| 1842 | + onManage={manageHandlersFor(app)} | |
| 1843 | + /> | |
| 1844 | + ))} | |
| 1845 | + </RadioGroup> | |
| 1846 | + ) : null} | |
| 1847 | + </div> | |
| 1848 | + )} | |
| 1850 | 1849 | |
| 1851 | − {oauthApps.length > 0 && ( | |
| 1852 | − <RadioGroup | |
| 1853 | − value={selectedApp} | |
| 1854 | − onValueChange={setPickedApp} | |
| 1855 | − className="gap-2" | |
| 1850 | + {oauthApps.length > 0 && ( | |
| 1851 | + <RadioGroup | |
| 1852 | + value={selectedApp} | |
| 1853 | + onValueChange={setPickedApp} | |
| 1854 | + className="gap-2" | |
| 1855 | + > | |
| 1856 | + {oauthApps.map((app: OAuthClientOption) => ( | |
| 1857 | + <OAuthAppRadioRow | |
| 1858 | + key={String(app.slug)} | |
| 1859 | + app={app} | |
| 1860 | + idPrefix="app" | |
| 1861 | + variant="matched" | |
| 1862 | + showOwnerLabel={ownerDisplay.showOwnerLabels} | |
| 1863 | + onManage={manageHandlersFor(app)} | |
| 1864 | + /> | |
| 1865 | + ))} | |
| 1866 | + <Button | |
| 1867 | + type="button" | |
| 1868 | + variant="outline" | |
| 1869 | + className="h-auto justify-start gap-3 rounded-lg border-dashed border-border/60 px-3 py-2.5 text-sm font-normal text-muted-foreground hover:text-foreground" | |
| 1870 | + onClick={() => setRegisteringOAuthClient(true)} | |
| 1856 | 1871 | > |
| 1857 | − {oauthApps.map((app: OAuthClientOption) => ( | |
| 1858 | − <OAuthAppRadioRow | |
| 1859 | − key={String(app.slug)} | |
| 1860 | − app={app} | |
| 1861 | − idPrefix="app" | |
| 1862 | − variant="matched" | |
| 1863 | − showOwnerLabel={ownerDisplay.showOwnerLabels} | |
| 1864 | − onManage={manageHandlersFor(app)} | |
| 1865 | − /> | |
| 1866 | − ))} | |
| 1867 | − <Button | |
| 1868 | − type="button" | |
| 1869 | − variant="outline" | |
| 1870 | − className="h-auto justify-start gap-3 rounded-lg border-dashed border-border/60 px-3 py-2.5 text-sm font-normal text-muted-foreground hover:text-foreground" | |
| 1871 | − onClick={() => setRegisteringOAuthClient(true)} | |
| 1872 | − > | |
| 1873 | − <PlusIcon className="size-4" /> | |
| 1874 | − Register a new app | |
| 1875 | − </Button> | |
| 1876 | − </RadioGroup> | |
| 1877 | − )} | |
| 1878 | − </div> | |
| 1879 | − ) | |
| 1880 | − ) : ( | |
| 1881 | − <CredentialValueFields | |
| 1882 | − inputs={credentialInputs} | |
| 1883 | − singleInput={singleInput} | |
| 1884 | − showLabels={isEnvMethod} | |
| 1885 | − affix={singleCredentialAffix} | |
| 1886 | − allowExternalProvider={!isEnvMethod} | |
| 1887 | − values={values} | |
| 1888 | − onValuesChange={setValues} | |
| 1889 | − origin={credentialOrigin} | |
| 1890 | − onOriginChange={(next) => { | |
| 1891 | − setCredentialOrigin(next); | |
| 1892 | − if (next === "paste") setOnePasswordItemId(""); | |
| 1893 | − }} | |
| 1894 | − onePasswordItemId={onePasswordItemId} | |
| 1895 | − onOnePasswordItemIdChange={setOnePasswordItemId} | |
| 1896 | − /> | |
| 1897 | − )} | |
| 1898 | − {isOAuth && oauthPopup.error ? ( | |
| 1899 | − <p className="text-xs text-destructive">{oauthPopup.error}</p> | |
| 1900 | − ) : null} | |
| 1901 | − </div> | |
| 1902 | − )} | |
| 1903 | − </TabsContent> | |
| 1904 | − )} | |
| 1872 | + <PlusIcon className="size-4" /> | |
| 1873 | + Register a new app | |
| 1874 | + </Button> | |
| 1875 | + </RadioGroup> | |
| 1876 | + )} | |
| 1877 | + </div> | |
| 1878 | + ) | |
| 1879 | + ) : ( | |
| 1880 | + <CredentialValueFields | |
| 1881 | + inputs={credentialInputs} | |
| 1882 | + singleInput={singleInput} | |
| 1883 | + showLabels={isEnvMethod} | |
| 1884 | + affix={singleCredentialAffix} | |
| 1885 | + allowExternalProvider={!isEnvMethod} | |
| 1886 | + values={values} | |
| 1887 | + onValuesChange={setValues} | |
| 1888 | + origin={credentialOrigin} | |
| 1889 | + onOriginChange={(next) => { | |
| 1890 | + setCredentialOrigin(next); | |
| 1891 | + if (next === "paste") setOnePasswordItemId(""); | |
| 1892 | + }} | |
| 1893 | + onePasswordItemId={onePasswordItemId} | |
| 1894 | + onOnePasswordItemIdChange={setOnePasswordItemId} | |
| 1895 | + /> | |
| 1896 | + )} | |
| 1897 | + {isOAuth && oauthPopup.error ? ( | |
| 1898 | + <p className="text-xs text-destructive">{oauthPopup.error}</p> | |
| 1899 | + ) : null} | |
| 1900 | + </div> | |
| 1901 | + )} | |
| 1902 | + </TabsContent> | |
| 1905 | 1903 | </Tabs> |
| 1906 | 1904 | )} |
| 1907 | 1905 | |