-
Notifications
You must be signed in to change notification settings - Fork 919
Add config.json onboarding flow for workspace setup scripts #224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| DATABASE_URL=postgresql://postgres:postgres@localhost:5432/superset | ||
| VITE_DEV_SERVER_PORT=4927 | ||
| WEBSITE_URL=http://localhost:3001 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| import { existsSync, mkdirSync, writeFileSync } from "node:fs"; | ||
| import { join } from "node:path"; | ||
| import { db } from "main/lib/db"; | ||
| import { z } from "zod"; | ||
| import { publicProcedure, router } from "../.."; | ||
|
|
||
| function configExists(mainRepoPath: string): boolean { | ||
| const configPath = join(mainRepoPath, ".superset", "config.json"); | ||
| return existsSync(configPath); | ||
| } | ||
|
|
||
| const CONFIG_TEMPLATE = `{ | ||
| "setup": [], | ||
| "teardown": [] | ||
| } | ||
| `; | ||
|
|
||
| function getConfigPath(mainRepoPath: string): string { | ||
| return join(mainRepoPath, ".superset", "config.json"); | ||
| } | ||
|
|
||
| function ensureConfigExists(mainRepoPath: string): string { | ||
| const configPath = getConfigPath(mainRepoPath); | ||
| const supersetDir = join(mainRepoPath, ".superset"); | ||
|
|
||
| if (!existsSync(configPath)) { | ||
| // Create .superset directory if it doesn't exist | ||
| if (!existsSync(supersetDir)) { | ||
| mkdirSync(supersetDir, { recursive: true }); | ||
| } | ||
| // Create config.json with template | ||
| writeFileSync(configPath, CONFIG_TEMPLATE, "utf-8"); | ||
| } | ||
|
|
||
| return configPath; | ||
| } | ||
|
|
||
| export const createConfigRouter = () => { | ||
| return router({ | ||
| // Check if we should show the config toast for a project | ||
| shouldShowConfigToast: publicProcedure | ||
| .input(z.object({ projectId: z.string() })) | ||
| .query(({ input }) => { | ||
| const project = db.data.projects.find((p) => p.id === input.projectId); | ||
| if (!project) { | ||
| return false; | ||
| } | ||
|
|
||
| // Don't show if already dismissed or if config exists | ||
| if (project.configToastDismissed) { | ||
| return false; | ||
| } | ||
|
|
||
| return !configExists(project.mainRepoPath); | ||
| }), | ||
|
|
||
| // Mark the config toast as dismissed for a project | ||
| dismissConfigToast: publicProcedure | ||
| .input(z.object({ projectId: z.string() })) | ||
| .mutation(async ({ input }) => { | ||
| await db.update((data) => { | ||
| const project = data.projects.find((p) => p.id === input.projectId); | ||
| if (project) { | ||
| project.configToastDismissed = true; | ||
| } | ||
| }); | ||
| return { success: true }; | ||
| }), | ||
|
|
||
| // Get the config file path (creates it if it doesn't exist) | ||
| getConfigFilePath: publicProcedure | ||
| .input(z.object({ projectId: z.string() })) | ||
| .query(({ input }) => { | ||
| const project = db.data.projects.find((p) => p.id === input.projectId); | ||
| if (!project) { | ||
| return null; | ||
| } | ||
| return ensureConfigExists(project.mainRepoPath); | ||
| }), | ||
| }); | ||
| }; | ||
|
|
||
| export type ConfigRouter = ReturnType<typeof createConfigRouter>; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export type { ConfigRouter } from "./config"; | ||
| export { createConfigRouter } from "./config"; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
149 changes: 149 additions & 0 deletions
149
apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| import { Button } from "@superset/ui/button"; | ||
| import { ButtonGroup } from "@superset/ui/button-group"; | ||
| import { | ||
| DropdownMenu, | ||
| DropdownMenuContent, | ||
| DropdownMenuItem, | ||
| DropdownMenuSeparator, | ||
| DropdownMenuTrigger, | ||
| } from "@superset/ui/dropdown-menu"; | ||
| import type { ExternalApp } from "main/lib/db/schemas"; | ||
| import { useState } from "react"; | ||
| import { HiChevronDown } from "react-icons/hi2"; | ||
| import { LuCopy } from "react-icons/lu"; | ||
| import cursorIcon from "renderer/assets/app-icons/cursor.svg"; | ||
| import finderIcon from "renderer/assets/app-icons/finder.png"; | ||
| import itermIcon from "renderer/assets/app-icons/iterm.png"; | ||
| import terminalIcon from "renderer/assets/app-icons/terminal.png"; | ||
| import vscodeIcon from "renderer/assets/app-icons/vscode.svg"; | ||
| import warpIcon from "renderer/assets/app-icons/warp.png"; | ||
| import xcodeIcon from "renderer/assets/app-icons/xcode.svg"; | ||
| import { trpc } from "renderer/lib/trpc"; | ||
|
|
||
| interface AppOption { | ||
| id: ExternalApp; | ||
| label: string; | ||
| icon: string; | ||
| } | ||
|
|
||
| const APP_OPTIONS: AppOption[] = [ | ||
| { id: "finder", label: "Finder", icon: finderIcon }, | ||
| { id: "cursor", label: "Cursor", icon: cursorIcon }, | ||
| { id: "vscode", label: "VS Code", icon: vscodeIcon }, | ||
| { id: "xcode", label: "Xcode", icon: xcodeIcon }, | ||
| { id: "iterm", label: "iTerm", icon: itermIcon }, | ||
| { id: "warp", label: "Warp", icon: warpIcon }, | ||
| { id: "terminal", label: "Terminal", icon: terminalIcon }, | ||
| ]; | ||
|
|
||
| const getAppOption = (id: ExternalApp) => | ||
| APP_OPTIONS.find((app) => app.id === id) ?? APP_OPTIONS[1]; | ||
|
|
||
| export interface OpenInButtonProps { | ||
| path: string | undefined; | ||
| /** Optional label to show next to the icon (e.g., folder name) */ | ||
| label?: string; | ||
| /** Show keyboard shortcut hints */ | ||
| showShortcuts?: boolean; | ||
| } | ||
|
|
||
| export function OpenInButton({ | ||
| path, | ||
| label, | ||
| showShortcuts = false, | ||
| }: OpenInButtonProps) { | ||
| const [isOpen, setIsOpen] = useState(false); | ||
| const utils = trpc.useUtils(); | ||
|
|
||
| const { data: lastUsedApp = "cursor" } = | ||
| trpc.settings.getLastUsedApp.useQuery(); | ||
|
|
||
| const openInApp = trpc.external.openInApp.useMutation({ | ||
| onSuccess: () => utils.settings.getLastUsedApp.invalidate(), | ||
| }); | ||
| const copyPath = trpc.external.copyPath.useMutation(); | ||
|
|
||
| const currentApp = getAppOption(lastUsedApp); | ||
|
|
||
| const handleOpenIn = (app: ExternalApp) => { | ||
| if (!path) return; | ||
| openInApp.mutate({ path, app }); | ||
| setIsOpen(false); | ||
| }; | ||
|
|
||
| const handleCopyPath = () => { | ||
| if (!path) return; | ||
| copyPath.mutate(path); | ||
| setIsOpen(false); | ||
| }; | ||
|
|
||
| const handleOpenLastUsed = () => { | ||
| if (!path) return; | ||
| openInApp.mutate({ path, app: lastUsedApp }); | ||
| }; | ||
|
|
||
| return ( | ||
| <ButtonGroup> | ||
| {label && ( | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| className="gap-1.5" | ||
| onClick={handleOpenLastUsed} | ||
| disabled={!path} | ||
| title={`Open in ${currentApp.label}${showShortcuts ? " (⌘O)" : ""}`} | ||
| > | ||
| <img src={currentApp.icon} alt="" className="size-4 object-contain" /> | ||
| <span className="font-medium">{label}</span> | ||
| </Button> | ||
| )} | ||
| <DropdownMenu open={isOpen} onOpenChange={setIsOpen}> | ||
| <DropdownMenuTrigger asChild> | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| className="gap-1" | ||
| disabled={!path} | ||
| > | ||
| <span>Open</span> | ||
| <HiChevronDown className="size-3" /> | ||
| </Button> | ||
| </DropdownMenuTrigger> | ||
| <DropdownMenuContent align="end" className="w-48"> | ||
| {APP_OPTIONS.map((app) => ( | ||
| <DropdownMenuItem | ||
| key={app.id} | ||
| onClick={() => handleOpenIn(app.id)} | ||
| className="flex items-center justify-between" | ||
| > | ||
| <div className="flex items-center gap-2"> | ||
| <img | ||
| src={app.icon} | ||
| alt={app.label} | ||
| className="size-4 object-contain" | ||
| /> | ||
| <span>{app.label}</span> | ||
| </div> | ||
| {showShortcuts && app.id === lastUsedApp && ( | ||
| <span className="text-xs text-muted-foreground">⌘O</span> | ||
| )} | ||
| </DropdownMenuItem> | ||
| ))} | ||
| <DropdownMenuSeparator /> | ||
| <DropdownMenuItem | ||
| onClick={handleCopyPath} | ||
| className="flex items-center justify-between" | ||
| > | ||
| <div className="flex items-center gap-2"> | ||
| <LuCopy className="size-4" /> | ||
| <span>Copy path</span> | ||
| </div> | ||
| {showShortcuts && ( | ||
| <span className="text-xs text-muted-foreground">⌘⇧C</span> | ||
| )} | ||
| </DropdownMenuItem> | ||
| </DropdownMenuContent> | ||
| </DropdownMenu> | ||
| </ButtonGroup> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export type { OpenInButtonProps } from "./OpenInButton"; | ||
| export { OpenInButton } from "./OpenInButton"; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for file system operations.
The
ensureConfigExistsfunction performs file system operations (mkdirSync,writeFileSync) without error handling. Operations can fail due to permissions, disk space, or other I/O issues, potentially causing unhandled exceptions.Consider wrapping in try-catch to provide better error feedback:
This ensures failures are caught and reported with context rather than causing silent crashes.
🤖 Prompt for AI Agents