Skip to content

Commit

Permalink
Onboarding (meltylabs#44)
Browse files Browse the repository at this point in the history
* [via melty] ci: Add stable-macos workflow for building and releasing

* [via melty] feat: Enhance Tasks component with ASCII art and workspace creation option

* [via melty] feat: Add Ascii component for animated text display

* [by melty] feat: Add createAndOpenWorkspace functionality

* [via melty] feat: Add 'createAndOpenWorkspace' to RpcMethod type

* [by melty] feat: Implement user-selected workspace creation

* [via melty] feat: Simplify workspace creation process

* [by melty] feat: Prevent workspace save prompt when opening new folder

* [by melty] feat: Add OnboardingSection component and integrate into Tasks

* [via melty] refactor: Remove Onboarding component and update Tasks view

* [via melty] chore: Comment out OnboardingSection component in Tasks.tsx

* [by melty] refactor: Simplify OnboardingSection component structure

* feat: Uncomment OnboardingSection component in Tasks.tsx

* fix: Improve time formatting in Tasks component

* [via melty] feat: Enhance OnboardingSection with interactive buttons

* [by melty] feat: Add onClick handlers to OnboardingSection buttons

* refactor: Improve OnboardingSection layout and styling

* [by melty] feat: Add navigation bar and help page

* help

* remove spaces

* [via melty] style: Remove unnecessary blank line in Tasks component

* [by melty] feat: Add onboarding flow to Melty extension

* [via melty] feat: Update onboarding process and add new RPC methods

* [by melty] feat: Enhance keyboard interaction feedback in Onboarding component

* [via melty] feat: Enhance onboarding flow and user experience

* [by melty] feat: Implement onboarding status methods in HelloWorldPanel

* [by melty] refactor: Move onboarding status methods to MeltyExtension class

* add type

* [via melty] feat: Update onboarding flow and add logging

* [by melty] feat: Implement automatic redirection after onboarding completion

* [via melty] refactor: Update onboarding flow and UI elements

* [by melty] fix: Improve onboarding flow and add loading state

* choose

* remove workflow
  • Loading branch information
cbh123 authored Sep 3, 2024
1 parent d898fdd commit 384d183
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 114 deletions.
36 changes: 36 additions & 0 deletions extensions/spectacular/src/HelloWorldPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { GitManager } from "./services/GitManager";
import { GitHubManager } from './services/GitHubManager';
import { TaskManager } from './services/TaskManager';
import posthog from "posthog-js";
import { create } from 'domain';

/**
* This class manages the state and behavior of HelloWorld webview panels.
Expand Down Expand Up @@ -212,6 +213,8 @@ export class HelloWorldPanel implements WebviewViewProvider {
return await this.rpcOpenWorkspaceDialog();
case "createGitRepository":
return await this.rpcCreateGitRepository();
case "createAndOpenWorkspace":
return await this.rpcCreateAndOpenWorkspace();
case "getActiveTask":
return await this.rpcGetActiveTask(params.taskId);
case "listMeltyFiles":
Expand Down Expand Up @@ -252,6 +255,10 @@ export class HelloWorldPanel implements WebviewViewProvider {
return await this.rpcGetAssistantDescription(params.assistantType);
case "getVSCodeTheme":
return this.rpcGetVSCodeTheme();
case "checkOnboardingComplete":
return this.rpcCheckOnboardingComplete();
case "setOnboardingComplete":
return this.rpcSetOnboardingComplete();
default:
throw new Error(`Unknown RPC method: ${method}`);
}
Expand Down Expand Up @@ -284,6 +291,35 @@ export class HelloWorldPanel implements WebviewViewProvider {
}
}

private async rpcCreateAndOpenWorkspace(): Promise<boolean> {
try {
const homedir = require('os').homedir();
const workspacePath = vscode.Uri.file(homedir + '/melty-workspace');

// Create the directory
await vscode.workspace.fs.createDirectory(workspacePath);

// Open the new workspace in the current window without prompting
const success = await vscode.commands.executeCommand('vscode.openFolder', workspacePath, {
forceNewWindow: false,
noRecentEntry: true
});

return success === undefined;
} catch (error) {
console.error("Failed to create and open workspace:", error);
return false;
}
}

private async rpcCheckOnboardingComplete(): Promise<boolean> {
return this.MeltyExtension.checkOnboardingComplete();
}

private async rpcSetOnboardingComplete(): Promise<void> {
await this.MeltyExtension.setOnboardingComplete();
}

private async rpcOpenWorkspaceDialog(): Promise<boolean> {
const result = await vscode.window.showOpenDialog({
canSelectFiles: false,
Expand Down
8 changes: 8 additions & 0 deletions extensions/spectacular/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ export class MeltyExtension {
clearInterval(this.branchCheckInterval);
}
}

public async checkOnboardingComplete(): Promise<boolean> {
return this.context.globalState.get('onboardingComplete', false);
}

public async setOnboardingComplete(): Promise<void> {
await this.context.globalState.update('onboardingComplete', true);
}
}

let outputChannel: vscode.OutputChannel;
Expand Down
5 changes: 4 additions & 1 deletion extensions/spectacular/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,7 @@ export type RpcMethod =
| "getAssistantDescription"
| "getVSCodeTheme"
| "openWorkspaceDialog"
| "createGitRepository";
| "createGitRepository"
| "createAndOpenWorkspace"
| "checkOnboardingComplete"
| "setOnboardingComplete";
63 changes: 37 additions & 26 deletions extensions/spectacular/webview-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import {
Route,
Routes,
Navigate,
useNavigate,
useLocation,
} from "react-router-dom";
import { Tasks } from "./components/Tasks";
import { ConversationView } from "./components/ConversationView";
import { Help } from "./components/Help";
import { NavBar } from "./components/NavBar";
import { Onboarding } from "./components/Onboarding";
import { EventManager } from './eventManager';
import { RpcClient } from "RpcClient";
Expand All @@ -20,45 +21,55 @@ const rpcClient = RpcClient.getInstance();
const ThemeContext = createContext<'light' | 'dark'>('light');

function AppContent() {
const navigate = useNavigate();
const location = useLocation();
const theme = useContext(ThemeContext);

const handleKeyDown = useCallback(
async (event: KeyboardEvent) => {
if ((event.metaKey || event.ctrlKey) && event.key === "[") {
event.preventDefault();
if (location.pathname !== "/") {
if (location.pathname.startsWith("/task/")) {
const taskId = location.pathname.split("/")[2]; // TODO there's gotta be a less hacky way...
await rpcClient.run("deactivateTask", { taskId })
}
navigate("/");
}
}
},
[navigate, location]
);
const [showOnboarding, setShowOnboarding] = useState<boolean | null>(null);
const location = useLocation();

useEffect(() => {
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
const checkOnboarding = async () => {
const onboardingComplete = await rpcClient.run("checkOnboardingComplete", {});
console.log("onboardingComplete", onboardingComplete);
setShowOnboarding(!onboardingComplete);
};
}, [handleKeyDown]);

useEffect(() => {
checkOnboarding();
return () => EventManager.Instance.cleanup();
}, []);

useEffect(() => {
if (showOnboarding === false && location.pathname === '/onboarding') {
// Redirect to home page after onboarding is complete
window.history.pushState(null, '', '/');
}
}, [showOnboarding, location.pathname]);

if (showOnboarding === null) {
return <div>Loading...</div>;
}

if (showOnboarding && location.pathname !== '/onboarding') {
return <Navigate to="/onboarding" replace />;
}

return (
<main className={theme === 'dark' ? 'dark' : ''}>
{!showOnboarding && <NavBar />}
<div className="bg-background text-foreground p-4">
<Routes>
<Route
path="/onboarding"
element={
<Onboarding
onComplete={() => {
setShowOnboarding(false);
rpcClient.run("setOnboardingComplete", {});
}}
/>
}
/>
<Route path="/task/:taskId" element={<ConversationView />} />
<Route path="/onboarding" element={<Onboarding />} />
<Route path="/" element={<Tasks />} />
<Route path="/help" element={<Help />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</div>
Expand Down Expand Up @@ -89,7 +100,7 @@ function App() {
EventManager.Instance.addListener('notification', handleNotification);

return () => {
EventManager.Instance.removeListener('notification', handleNotification); // probably don't need but can't hurt
EventManager.Instance.removeListener('notification', handleNotification);
EventManager.Instance.cleanup();
};
}, [initTheme]);
Expand Down
41 changes: 41 additions & 0 deletions extensions/spectacular/webview-ui/src/components/Ascii.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useState, useEffect } from 'react';

const Ascii = () => {
const [text, setText] = useState('');
const fullText = ` _ _
_ __ ___ ___| | |_ _ _
| '_ \` _ \\ / _ \\ | __| | | |
| | | | | | __/ | |_| |_| |
|_| |_| |_|\\___|_|\\__|\\__, |
|___/`;

useEffect(() => {
let index = 0;
const timer = setInterval(() => {
setText((prev) => prev + fullText[index]);
index++;
if (index === fullText.length) {
clearInterval(timer);
}
}, 5); // Adjust this value to control the speed

return () => clearInterval(timer);
}, []);

return (
<pre
style={{
fontFamily: 'monospace',
whiteSpace: 'pre',
display: 'block',
padding: '1em',
borderRadius: '4px',
lineHeight: '1',
}}
>
{text}
</pre>
);
};

export default Ascii;
14 changes: 14 additions & 0 deletions extensions/spectacular/webview-ui/src/components/Help.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

export const Help: React.FC = () => {
return (
<div className="prose mx-auto">
<h3>Need some help? Noticed a bug? Have a cool idea?</h3>

<p>Just text me! I'd love to help. You're one of our early users, so your feedback is really helpful for us.</p>

<p>You can reach Charlie (CEO) at +1 646-761-1319.</p>
<p>Or, email us at [email protected]</p>
</div >
);
};
28 changes: 28 additions & 0 deletions extensions/spectacular/webview-ui/src/components/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { HelpCircle } from 'lucide-react';

export const NavBar: React.FC = () => {
const location = useLocation();

return (
<nav className="mb-6 mt-4 mx-3 relative">
<ul className="flex justify-between">
<li></li>
<li>
<Link to="/">
<h1 className="text-3xl font-extrabold tracking-tighter text-center">
melty
</h1>
</Link>
</li>
<li>
</li>
</ul>

<Link to="/help" className="absolute right-4 top-2">
<HelpCircle />
</Link>
</nav>
);
};
Loading

0 comments on commit 384d183

Please sign in to comment.