Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions desktop/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>flow Desktop</title>
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script type="module" src="/src/root.tsx"></script>
</body>
</html>
265 changes: 139 additions & 126 deletions desktop/package-lock.json

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@
"@tauri-apps/plugin-shell": "^2.2.2",
"@types/prismjs": "^1.26.5",
"prismjs": "^1.30.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-markdown": "^10.1.0"
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-markdown": "^10.1.0",
"wouter": "^3.7.1"
},
"devDependencies": {
"@chromatic-com/storybook": "^4.0.0",
Expand All @@ -40,8 +41,8 @@
"@storybook/react-vite": "^9.0.4",
"@tauri-apps/cli": "^2",
"@types/node": "^20.11.24",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.1",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0",
"@vitejs/plugin-react": "^4.3.4",
"@vitest/browser": "^3.2.1",
"@vitest/coverage-v8": "^3.2.1",
Expand Down
143 changes: 41 additions & 102 deletions desktop/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import "@mantine/core/styles.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useEffect, useState } from "react";
import { Route, Switch } from "wouter";
import "./App.css";
import { useBackendData, useExecutable } from "./hooks/useBackendData";
import { NotifierProvider, useNotifier } from "./hooks/useNotifier";
import { SettingsProvider } from "./hooks/useSettings";
import { AppShell, View, Viewer } from "./layout";
import { ThemeProvider } from "./theme/ThemeProvider";
import { NotificationType } from "./types/notification";
import { AppProvider } from "./hooks/useAppContext.tsx";
import { NotifierProvider } from "./hooks/useNotifier";
import { AppShell } from "./layout";
import { PageWrapper } from "./components/PageWrapper.tsx";
import { Settings, Welcome, Data } from "./pages";
import { WorkspaceRoute } from "./pages/Workspace/WorkspaceRoute.tsx";
import { ExecutableRoute } from "./pages/Executable/ExecutableRoute.tsx";
import { Text } from "@mantine/core";

const queryClient = new QueryClient({
defaultOptions: {
Expand All @@ -18,104 +19,42 @@ const queryClient = new QueryClient({
},
});

function AppContent() {
const [currentView, setCurrentView] = useState<View>(View.Welcome);
const [welcomeMessage, setWelcomeMessage] = useState<string>("");
const [selectedExecutable, setSelectedExecutable] = useState<string | null>(
null
);
const [selectedWorkspace, setSelectedWorkspace] = useState<string | null>(
null
);
const { notification, setNotification } = useNotifier();

const { config, workspaces, executables, isLoading, hasError, refreshAll } =
useBackendData(selectedWorkspace);

const { executable, executableError } = useExecutable(
selectedExecutable || ""
);

// Set initial workspace from config when it loads
useEffect(() => {
if (config?.currentWorkspace && workspaces && workspaces.length > 0) {
// Only update if we don't have a selected workspace or if the config workspace is different
if (!selectedWorkspace || config.currentWorkspace !== selectedWorkspace) {
setSelectedWorkspace(config.currentWorkspace);
}
}
}, [config, workspaces]);

useEffect(() => {
if (hasError) {
setNotification({
title: "Unexpected error",
message: hasError.message || "An error occurred",
type: NotificationType.Error,
autoClose: false,
});
}
}, [hasError]);

useEffect(() => {
if (welcomeMessage === "" && executables?.length > 0) {
setWelcomeMessage("Select an executable to get started.");
}
}, [executables, welcomeMessage]);

const handleLogoClick = () => {
setCurrentView(View.Welcome);
};

return (
<AppShell
currentView={currentView}
setCurrentView={(view: string) => setCurrentView(view as View)}
workspaces={workspaces || []}
selectedWorkspace={selectedWorkspace}
onSelectWorkspace={(workspaceName) => {
setSelectedWorkspace(workspaceName);
setCurrentView(View.Workspace);
}}
visibleExecutables={executables || []}
onSelectExecutable={(executable) => {
if (executable === selectedExecutable) {
return;
}
setSelectedExecutable(executable);
if (currentView !== View.Executable) {
setCurrentView(View.Executable);
}
}}
onLogoClick={handleLogoClick}
hasError={hasError}
isLoading={isLoading}
refreshAll={refreshAll}
notification={notification}
setNotification={setNotification}
>
<Viewer
currentView={currentView}
selectedExecutable={executable}
executableError={executableError}
welcomeMessage={welcomeMessage}
workspace={
workspaces?.find((w) => w.name === selectedWorkspace) || null
}
/>
</AppShell>
);
}

function App() {
return (
<QueryClientProvider client={queryClient}>
<NotifierProvider>
<SettingsProvider>
<ThemeProvider>
<AppContent />
</ThemeProvider>
</SettingsProvider>
<AppProvider>
<AppShell>
<Switch>
<Route path="/">
<PageWrapper>
<Welcome />
</PageWrapper>
</Route>
<Route
path="/workspace/:workspaceName"
component={WorkspaceRoute}
/>
<Route
path="/executable/:executableId"
component={ExecutableRoute}
/>
<Route path="/logs">
<PageWrapper>
<Text>Logs view coming soon...</Text>
</PageWrapper>
</Route>
<Route path="/vault" component={Data} />
<Route path="/cache" component={Data} />
<Route path="/settings" component={Settings} />
<Route>
<PageWrapper>
<Welcome welcomeMessage="404: What you are looking for couldn't be found" />
</PageWrapper>
</Route>
</Switch>
</AppShell>
</AppProvider>
</NotifierProvider>
</QueryClientProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ NC='\\033[0m' # No Color

# Function to log messages
log() {
echo -e "\${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]\${NC} \$1" | tee -a "\$LOG_FILE"
echo -e "\${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]\${NC} $1" | tee -a "\$LOG_FILE"
}

# Function to handle errors
error() {
echo -e "\${RED}[ERROR]\${NC} \$1" >&2
echo -e "\${RED}[ERROR]\${NC} $1" >&2
exit 1
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export function CodeHighlighter({
type: NotificationType.Error,
autoClose: true,
});
console.error(error);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ export function MarkdownRenderer({
pre: (props: ComponentPropsWithoutRef<typeof Code>) => {
const codeElement = props.children as React.ReactElement;
const codeContent = codeElement?.props?.children || "";
return <CodeHighlighter theme={settings.theme}>{codeContent}</CodeHighlighter>;
return (
<CodeHighlighter theme={settings.theme}>
{codeContent}
</CodeHighlighter>
);
},
}}
>
Expand Down
16 changes: 16 additions & 0 deletions desktop/src/components/PageWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ScrollArea } from "@mantine/core";

export function PageWrapper({ children }: { children: React.ReactNode }) {
return (
<ScrollArea
h="calc(100vh - var(--app-header-height) - var(--app-shell-padding-total))"
w="calc(100vw - var(--app-navbar-width) - var(--app-shell-padding-total))"
type="auto"
scrollbarSize={6}
scrollHideDelay={100}
offsetScrollbars
>
{children}
</ScrollArea>
);
}
25 changes: 16 additions & 9 deletions desktop/src/components/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ export function SettingRow({ label, description, children }: SettingRowProps) {
<Box py="md">
<Group align="flex-start" gap="xl">
<Box className={styles.settingLabel}>
<Text size="sm" fw={500}>{label}</Text>
<Text size="sm" fw={500}>
{label}
</Text>
{description && (
<Text size="xs" c="dimmed" mt={2}>{description}</Text>
<Text size="xs" c="dimmed" mt={2}>
{description}
</Text>
)}
</Box>
<Box className={styles.settingControl}>
{children}
</Box>
<Box className={styles.settingControl}>{children}</Box>
</Group>
</Box>
);
Expand All @@ -33,12 +35,17 @@ interface SettingSectionProps {
export function SettingSection({ title, children }: SettingSectionProps) {
return (
<Box mb="lg">
<Text size="xs" fw={500} mb="xs" c="dimmed" tt="uppercase" className={styles.sectionTitle}>
<Text
size="xs"
fw={500}
mb="xs"
c="dimmed"
tt="uppercase"
className={styles.sectionTitle}
>
{title}
</Text>
<Paper className={styles.settingCard}>
{children}
</Paper>
<Paper className={styles.settingCard}>{children}</Paper>
</Box>
);
}
Loading