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
7 changes: 7 additions & 0 deletions desktop/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-markdown": "^10.1.0",
"remove-markdown": "^0.5.0",
"wouter": "^3.7.1"
},
"devDependencies": {
Expand Down
33 changes: 31 additions & 2 deletions desktop/src-tauri/src/commands/executable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,47 @@ impl<E: CommandExecutor + 'static> ExecutableCommands<E> {
&self,
workspace: Option<&str>,
namespace: Option<&str>,
tags: Option<&[&str]>,
verb: Option<&str>,
filter: Option<&str>,
) -> CommandResult<Vec<Executable>> {
let mut args = vec!["browse", "--list"];

if let Some(ws) = workspace {
args.extend_from_slice(&["--workspace", ws]);
if !ws.is_empty() {
args.extend_from_slice(&["--workspace", ws]);
}
}

if let Some(ns) = namespace {
args.extend_from_slice(&["--namespace", ns]);
if !ns.is_empty() {
args.extend_from_slice(&["--namespace", ns]);
} else {
args.push("--all");
}
} else {
args.push("--all");
}

if let Some(tags) = tags {
for tag in tags {
if !tag.is_empty() {
args.extend_from_slice(&["--tag", tag]);
}
}
}

if let Some(verb) = verb {
if !verb.is_empty() {
args.extend_from_slice(&["--verb", verb]);
}
}

if let Some(filter) = filter {
if !filter.is_empty() {
args.extend_from_slice(&["--filter", filter]);
}
}

let response: ExecutableResponse = self.executor.execute_json(&args).await?;
Ok(response.executables)
Expand Down
17 changes: 16 additions & 1 deletion desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,26 @@ async fn get_executable(executable_ref: String) -> Result<enriched::Executable,
async fn list_executables(
workspace: Option<String>,
namespace: Option<String>,
tags: Option<Vec<String>>,
verb: Option<String>,
filter: Option<String>,
) -> Result<Vec<enriched::Executable>, String> {
let runner = cli::cli_executor();

// Convert owned Strings into borrowed &str slices expected by the command layer
let tags_ref_vec: Option<Vec<&str>> = tags
.as_ref()
.map(|v| v.iter().map(|s| s.as_str()).collect());

runner
.executable
.list(workspace.as_deref(), namespace.as_deref())
.list(
workspace.as_deref(),
namespace.as_deref(),
tags_ref_vec.as_deref(),
verb.as_deref(),
filter.as_deref(),
)
.await
.map_err(|e| e.to_string())
}
Expand Down
15 changes: 9 additions & 6 deletions desktop/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { Route, Switch } from "wouter";
import "./App.css";
import { AppProvider } from "./hooks/useAppContext.tsx";
import { AppProvider } from "./hooks/useAppContext";
import { NotifierProvider } from "./hooks/useNotifier";
import { AppShell } from "./layout";
import { PageWrapper } from "./components/PageWrapper.tsx";
import {Settings, Welcome, Data, Workspaces} from "./pages";
import { Workspace } from "./pages/Workspace/Workspace.tsx";
import { ExecutableRoute } from "./pages/Executable/ExecutableRoute.tsx";
import { PageWrapper } from "./components/PageWrapper";
import {Settings, Welcome, Data, Workspaces, Executables, Executable} from "./pages";
import { Workspace } from "./pages/Workspace/Workspace";
import { Text } from "@mantine/core";

const queryClient = new QueryClient({
Expand Down Expand Up @@ -35,13 +34,17 @@ function App() {
path="/workspaces"
component={Workspaces}
/>
<Route
path="/executables"
component={Executables}
/>
<Route
path="/workspace/:workspaceName"
component={Workspace}
/>
<Route
path="/executable/:executableId"
component={ExecutableRoute}
component={Executable}
/>
<Route path="/logs">
<PageWrapper>
Expand Down
18 changes: 2 additions & 16 deletions desktop/src/hooks/useAppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import React from "react";
import { createContext, useContext, useState, useEffect } from "react";
import { Config } from "../types/generated/config";
import { EnrichedWorkspace } from "../types/workspace";
import { EnrichedExecutable } from "../types/executable";
import { useConfig } from "./useConfig";
import { useWorkspaces } from "./useWorkspace";
import { useExecutables } from "./useExecutable";
import { invoke } from "@tauri-apps/api/core";
import { useQuery } from "@tanstack/react-query";

Expand All @@ -14,7 +12,6 @@ interface AppContextType {
selectedWorkspace: string | null;
setSelectedWorkspace: (workspaceName: string | null) => void;
workspaces: EnrichedWorkspace[];
executables: EnrichedExecutable[];
isLoading: boolean;
hasError: Error | null;
refreshAll: () => void;
Expand Down Expand Up @@ -78,24 +75,16 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
}
}, [config, workspaces, selectedWorkspace]);

const {
executables,
isExecutablesLoading,
executablesError,
refreshExecutables,
} = useExecutables(selectedWorkspace, enabled);

const isLoading =
isConfigLoading || isWorkspacesLoading || isExecutablesLoading;
const hasError = configError || workspacesError || executablesError;
isConfigLoading || isWorkspacesLoading;
const hasError = configError || workspacesError;
if (hasError) {
console.error("Error", hasError);
}

const refreshAll = () => {
refreshConfig();
refreshWorkspaces();
refreshExecutables();
};

// If flow binary is not available, return early with error state
Expand All @@ -107,7 +96,6 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
workspaces: [],
selectedWorkspace,
setSelectedWorkspace,
executables: [],
isLoading: false,
hasError: binaryCheckError,
refreshAll: () => {},
Expand All @@ -127,7 +115,6 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
workspaces: [],
selectedWorkspace,
setSelectedWorkspace,
executables: [],
isLoading: true,
hasError: null,
refreshAll: () => {},
Expand All @@ -145,7 +132,6 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
workspaces: workspaces || [],
selectedWorkspace,
setSelectedWorkspace,
executables,
isLoading,
hasError,
refreshAll,
Expand Down
42 changes: 30 additions & 12 deletions desktop/src/hooks/useExecutable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,32 +47,50 @@ export function useExecutable(executableRef: string) {
}

export function useExecutables(
selectedWorkspace: string | null,
enabled: boolean = true,
workspace: string | null,
namespace: string | null,
tags: string[] | null,
verb: string | null,
filter: string | null,
) {
const queryClient = useQueryClient();

const normalizedParams = React.useMemo(() => {
return {
workspace: workspace || undefined,
namespace: namespace || undefined,
tags: tags && tags.length > 0 ? tags : undefined,
verb: verb || undefined,
filter: filter || undefined,
};
}, [workspace, namespace, tags, verb, filter]);

const queryKey = React.useMemo(() => {
return ["executables", normalizedParams];
}, [normalizedParams]);

const {
data: executables,
isLoading: isExecutablesLoading,
error: executablesError,
} = useQuery({
queryKey: ["executables", selectedWorkspace],
queryKey,
queryFn: async () => {
if (!selectedWorkspace) return [];
console.log('Fetching executables with params:', normalizedParams);
return await invoke<EnrichedExecutable[]>("list_executables", {
workspace: selectedWorkspace,
workspace: normalizedParams.workspace,
namespace: normalizedParams.namespace,
tags: normalizedParams.tags,
verb: normalizedParams.verb,
filter: normalizedParams.filter,
});
},
enabled: enabled && !!selectedWorkspace, // Only run when workspace is selected AND enabled
});

const refreshExecutables = () => {
if (selectedWorkspace) {
queryClient.invalidateQueries({
queryKey: ["executables", selectedWorkspace],
});
}
void queryClient.invalidateQueries({
queryKey,
});
};

return {
Expand All @@ -81,4 +99,4 @@ export function useExecutables(
executablesError,
refreshExecutables,
};
}
}
Loading