storkit: merge 446_story_oauth_login_button_in_web_ui
This commit is contained in:
@@ -6,6 +6,7 @@ import type { AgentConfigInfo } from "../api/agents";
|
||||
import { agentsApi } from "../api/agents";
|
||||
import type {
|
||||
AnthropicModelInfo,
|
||||
OAuthStatus,
|
||||
PipelineState,
|
||||
WizardStateData,
|
||||
} from "../api/client";
|
||||
@@ -164,9 +165,10 @@ const getContextWindowSize = (
|
||||
interface ChatProps {
|
||||
projectPath: string;
|
||||
onCloseProject: () => void;
|
||||
oauthStatus?: OAuthStatus | null;
|
||||
}
|
||||
|
||||
export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
||||
export function Chat({ projectPath, onCloseProject, oauthStatus = null }: ChatProps) {
|
||||
const { messages, setMessages, clearMessages } = useChatHistory(projectPath);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [model, setModel] = useState("claude-code-pty");
|
||||
@@ -940,6 +942,7 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
|
||||
enableTools={enableTools}
|
||||
onToggleTools={setEnableTools}
|
||||
wsConnected={wsConnected}
|
||||
oauthStatus={oauthStatus}
|
||||
/>
|
||||
|
||||
{/* Two-column content area */}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from "react";
|
||||
import type { OAuthStatus } from "../api/client";
|
||||
import { api } from "../api/client";
|
||||
|
||||
const { useState, useEffect } = React;
|
||||
@@ -32,6 +33,7 @@ interface ChatHeaderProps {
|
||||
enableTools: boolean;
|
||||
onToggleTools: (enabled: boolean) => void;
|
||||
wsConnected: boolean;
|
||||
oauthStatus?: OAuthStatus | null;
|
||||
}
|
||||
|
||||
const getContextEmoji = (percentage: number): string => {
|
||||
@@ -55,6 +57,7 @@ export function ChatHeader({
|
||||
enableTools,
|
||||
onToggleTools,
|
||||
wsConnected,
|
||||
oauthStatus = null,
|
||||
}: ChatHeaderProps) {
|
||||
const hasModelOptions = availableModels.length > 0 || claudeModels.length > 0;
|
||||
const [showConfirm, setShowConfirm] = useState(false);
|
||||
@@ -340,6 +343,59 @@ export function ChatHeader({
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "16px" }}>
|
||||
{oauthStatus !== null &&
|
||||
(!oauthStatus.authenticated || oauthStatus.expired) && (
|
||||
<button
|
||||
type="button"
|
||||
title="Authenticate with Claude via OAuth"
|
||||
onClick={() => {
|
||||
window.open("/oauth/authorize", "_blank", "noopener,noreferrer");
|
||||
}}
|
||||
style={{
|
||||
padding: "6px 12px",
|
||||
borderRadius: "99px",
|
||||
border: "none",
|
||||
fontSize: "0.85em",
|
||||
backgroundColor: "#1a3a5c",
|
||||
color: "#7eb8f7",
|
||||
cursor: "pointer",
|
||||
outline: "none",
|
||||
transition: "all 0.2s",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
onMouseOver={(e) => {
|
||||
e.currentTarget.style.backgroundColor = "#234d7a";
|
||||
e.currentTarget.style.color = "#a8d4ff";
|
||||
}}
|
||||
onMouseOut={(e) => {
|
||||
e.currentTarget.style.backgroundColor = "#1a3a5c";
|
||||
e.currentTarget.style.color = "#7eb8f7";
|
||||
}}
|
||||
onFocus={(e) => {
|
||||
e.currentTarget.style.backgroundColor = "#234d7a";
|
||||
e.currentTarget.style.color = "#a8d4ff";
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
e.currentTarget.style.backgroundColor = "#1a3a5c";
|
||||
e.currentTarget.style.color = "#7eb8f7";
|
||||
}}
|
||||
>
|
||||
{oauthStatus.expired ? "Re-authenticate" : "Login with Claude"}
|
||||
</button>
|
||||
)}
|
||||
{oauthStatus?.authenticated && !oauthStatus.expired && (
|
||||
<span
|
||||
title="Authenticated with Claude via OAuth"
|
||||
style={{
|
||||
fontSize: "0.8em",
|
||||
color: "#4caf50",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
✓ Claude
|
||||
</span>
|
||||
)}
|
||||
|
||||
<div
|
||||
style={{
|
||||
fontSize: "0.75em",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { KeyboardEvent } from "react";
|
||||
import type { OAuthStatus } from "../../api/client";
|
||||
import { ProjectPathInput } from "./ProjectPathInput.tsx";
|
||||
import { RecentProjectsList } from "./RecentProjectsList.tsx";
|
||||
|
||||
@@ -24,6 +25,7 @@ export interface SelectionScreenProps {
|
||||
onCloseSuggestions: () => void;
|
||||
completionError: string | null;
|
||||
currentPartial: string;
|
||||
oauthStatus?: OAuthStatus | null;
|
||||
}
|
||||
|
||||
export function SelectionScreen({
|
||||
@@ -43,6 +45,7 @@ export function SelectionScreen({
|
||||
onCloseSuggestions,
|
||||
completionError,
|
||||
currentPartial,
|
||||
oauthStatus = null,
|
||||
}: SelectionScreenProps) {
|
||||
const resolvedHomeDir = homeDir
|
||||
? homeDir.endsWith("/")
|
||||
@@ -57,6 +60,37 @@ export function SelectionScreen({
|
||||
<h1>Storkit</h1>
|
||||
<p>Paste or complete a project path to start.</p>
|
||||
|
||||
{oauthStatus !== null && (
|
||||
<div style={{ marginBottom: "1rem" }}>
|
||||
{!oauthStatus.authenticated || oauthStatus.expired ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
window.open("/oauth/authorize", "_blank", "noopener,noreferrer");
|
||||
}}
|
||||
style={{
|
||||
padding: "8px 16px",
|
||||
borderRadius: "6px",
|
||||
border: "1px solid #1a3a5c",
|
||||
backgroundColor: "#1a3a5c",
|
||||
color: "#7eb8f7",
|
||||
cursor: "pointer",
|
||||
fontSize: "0.9em",
|
||||
}}
|
||||
>
|
||||
{oauthStatus.expired ? "Re-authenticate with Claude" : "Login with Claude"}
|
||||
</button>
|
||||
) : (
|
||||
<span
|
||||
title="Authenticated with Claude via OAuth"
|
||||
style={{ color: "#4caf50", fontSize: "0.9em" }}
|
||||
>
|
||||
✓ Authenticated with Claude
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{knownProjects.length > 0 && (
|
||||
<RecentProjectsList
|
||||
projects={knownProjects}
|
||||
|
||||
Reference in New Issue
Block a user