From b28fe3d49e5701282c21f6fbc090dded17afdc43 Mon Sep 17 00:00:00 2001 From: Joey Yu Date: Tue, 19 Mar 2024 15:40:48 -0400 Subject: [PATCH 1/5] chore: refactor cloud panel a bit --- src/renderer/index.tsx | 14 ++- .../components/CloudPanel.tsx | 96 +++++++++++++------ 2 files changed, 77 insertions(+), 33 deletions(-) diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index 4cb5e8dfb..d1a86bd4a 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -14,8 +14,10 @@ import { HashRouter } from "react-router-dom"; import { AuthContextProvider } from "./context/auth.context"; import { ThemeProvider } from "./providers/theme-provider"; import { TestSequencerWSProvider } from "./context/testSequencerWS.context"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; const root = createRoot(document.getElementById("root") as HTMLElement); +const queryClient = new QueryClient(); function fallbackRender({ error, resetErrorBoundary }) { return ; @@ -26,11 +28,13 @@ root.render( - - - - - + + + + + + + , diff --git a/src/renderer/routes/test_sequencer_panel/components/CloudPanel.tsx b/src/renderer/routes/test_sequencer_panel/components/CloudPanel.tsx index 8130a9eac..933c1131a 100644 --- a/src/renderer/routes/test_sequencer_panel/components/CloudPanel.tsx +++ b/src/renderer/routes/test_sequencer_panel/components/CloudPanel.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { Input } from "@/renderer/components/ui/input"; import { useTestSequencerState } from "@/renderer/hooks/useTestSequencerState"; import LockableButton from "./lockable/LockedButtons"; @@ -14,38 +14,84 @@ import { Button } from "@/renderer/components/ui/button"; import { useAppStore } from "@/renderer/stores/app"; import { useShallow } from "zustand/react/shallow"; import { testSequenceExportCloud } from "@/renderer/routes/test_sequencer_panel/models/models"; -import { Project, getCloudProjects } from "@/renderer/lib/api"; +import { getCloudProjects, getEnvironmentVariables } from "@/renderer/lib/api"; import { toastQueryError } from "@/renderer/utils/report-error"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { Spinner } from "@/renderer/components/ui/spinner"; export function CloudPanel() { + const queryClient = useQueryClient(); const [hardwareId, setHardwareId] = useState(""); const [projectId, setProjectId] = useState(""); const { tree, setIsLocked } = useTestSequencerState(); const { tSSendJsonMessage } = useTestSequencerWS(); - const [projects, setProjects] = useState([]); - const { setIsEnvVarModalOpen } = useAppStore( + const envsQuery = useQuery({ + queryKey: ["envs"], + queryFn: async () => { + const res = await getEnvironmentVariables(); + return res.match( + (vars) => vars, + (e) => { + toastQueryError(e, "Failed to fetch environment variables"); + return []; + }, + ); + }, + }); + + const projectsQuery = useQuery({ + queryKey: ["projects"], + queryFn: async () => { + if (envsQuery.isSuccess) { + if (envsQuery.data.some((c) => c.key === "FLOJOY_CLOUD_KEY")) { + const res = await getCloudProjects(); + return res.match( + (vars) => vars, + (e) => { + toastQueryError(e, "Failed to fetch cloud projects"); + return []; + }, + ); + } + } + return []; + }, + enabled: envsQuery.isSuccess, + }); + + const { isEnvVarModalOpen, setIsEnvVarModalOpen } = useAppStore( useShallow((state) => ({ + isEnvVarModalOpen: state.isEnvVarModalOpen, setIsEnvVarModalOpen: state.setIsEnvVarModalOpen, })), ); + useEffect(() => { + queryClient.invalidateQueries({ queryKey: ["envs"] }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isEnvVarModalOpen]); + const handleExport = () => { - setIsLocked(true); tSSendJsonMessage(testSequenceExportCloud(tree, hardwareId, projectId)); setIsLocked(true); }; - const fetchProjects = useCallback(async () => { - (await getCloudProjects()).match( - (p) => setProjects(p), - (e) => toastQueryError(e, "Failed to fetch projects from Flojoy Cloud"), - ); - }, []); + if (!envsQuery.isSuccess || !projectsQuery.isSuccess) { + return ; + } - useEffect(() => { - fetchProjects(); - }, [fetchProjects]); + const isCloudKeySet = envsQuery.data.some( + (c) => c.key === "FLOJOY_CLOUD_KEY", + ); + + if (!isCloudKeySet) { + return ( + + ); + } return (
@@ -75,24 +121,18 @@ export function CloudPanel() { - {projects.length === 0 && ( + {projectsQuery.data.length === 0 && (
No projects found -

Did you forget to set Flojoy Cloud API key?

-
- - -
+
)} - {projects.map((option) => ( + {projectsQuery.data.map((option) => ( {option.label} From f579c87b3613889833482de08b9c14cc26edb20b Mon Sep 17 00:00:00 2001 From: Joey Yu Date: Tue, 19 Mar 2024 15:55:23 -0400 Subject: [PATCH 2/5] chore: api key -> secret --- .../FLOJOY_CLOUD_DOWNLOAD/FLOJOY_CLOUD_DOWNLOAD.py | 4 ++-- .../FLOJOY_CLOUD_UPLOAD/FLOJOY_CLOUD_UPLOAD.py | 4 ++-- captain/routes/cloud.py | 4 ++-- captain/utils/test_sequencer/run_test_sequence.py | 2 +- playwright-test/10_env_modal.spec.ts | 4 ++-- .../flow_chart/views/env-var/EnvVarModal.tsx | 14 ++++++-------- .../test_sequencer_panel/components/CloudPanel.tsx | 4 ++-- 7 files changed, 17 insertions(+), 19 deletions(-) diff --git a/blocks/ETL/LOAD/CLOUD_DATABASE/FLOJOY_CLOUD_DOWNLOAD/FLOJOY_CLOUD_DOWNLOAD.py b/blocks/ETL/LOAD/CLOUD_DATABASE/FLOJOY_CLOUD_DOWNLOAD/FLOJOY_CLOUD_DOWNLOAD.py index 4e3009774..9ab654644 100644 --- a/blocks/ETL/LOAD/CLOUD_DATABASE/FLOJOY_CLOUD_DOWNLOAD/FLOJOY_CLOUD_DOWNLOAD.py +++ b/blocks/ETL/LOAD/CLOUD_DATABASE/FLOJOY_CLOUD_DOWNLOAD/FLOJOY_CLOUD_DOWNLOAD.py @@ -16,7 +16,7 @@ @node_preflight def preflight(): - api_key = get_env_var("FLOJOY_CLOUD_KEY") + api_key = get_env_var("FLOJOY_CLOUD_WORKSPACE_SECRET") if api_key is None: raise KeyError( @@ -41,7 +41,7 @@ def FLOJOY_CLOUD_DOWNLOAD( The downloaded DataContainer will be returned as it is. """ - api_key = get_env_var("FLOJOY_CLOUD_KEY") + api_key = get_env_var("FLOJOY_CLOUD_WORKSPACE_SECRET") if api_key is None: raise KeyError( diff --git a/blocks/ETL/LOAD/CLOUD_DATABASE/FLOJOY_CLOUD_UPLOAD/FLOJOY_CLOUD_UPLOAD.py b/blocks/ETL/LOAD/CLOUD_DATABASE/FLOJOY_CLOUD_UPLOAD/FLOJOY_CLOUD_UPLOAD.py index a1d676b3c..7c0d7f0c5 100644 --- a/blocks/ETL/LOAD/CLOUD_DATABASE/FLOJOY_CLOUD_UPLOAD/FLOJOY_CLOUD_UPLOAD.py +++ b/blocks/ETL/LOAD/CLOUD_DATABASE/FLOJOY_CLOUD_UPLOAD/FLOJOY_CLOUD_UPLOAD.py @@ -26,7 +26,7 @@ @node_preflight def preflight(): - api_key = get_env_var("FLOJOY_CLOUD_KEY") + api_key = get_env_var("FLOJOY_CLOUD_WORKSPACE_SECRET") if api_key is None: raise KeyError( @@ -65,7 +65,7 @@ def FLOJOY_CLOUD_UPLOAD( The input DataContainer will be returned as it is. """ - api_key = get_env_var("FLOJOY_CLOUD_KEY") + api_key = get_env_var("FLOJOY_CLOUD_WORKSPACE_SECRET") if api_key is None: raise KeyError( diff --git a/captain/routes/cloud.py b/captain/routes/cloud.py index bf0dfcbab..bb3eb9e4b 100644 --- a/captain/routes/cloud.py +++ b/captain/routes/cloud.py @@ -12,11 +12,11 @@ async def get_cloud_projects(): """ Get all projects from the Flojoy Cloud. """ - workspace_secret = get_env_var("FLOJOY_CLOUD_KEY") + workspace_secret = get_env_var("FLOJOY_CLOUD_WORKSPACE_SECRET") if workspace_secret is None: return Response(status_code=401, content=json.dumps([])) - cloud = FlojoyCloud(workspace_secret=get_env_var("FLOJOY_CLOUD_KEY")) + cloud = FlojoyCloud(workspace_secret=get_env_var("FLOJOY_CLOUD_WORKSPACE_SECRET")) projects = cloud.get_all_projects( "" diff --git a/captain/utils/test_sequencer/run_test_sequence.py b/captain/utils/test_sequencer/run_test_sequence.py index 17a705fc2..bfe8732a8 100644 --- a/captain/utils/test_sequencer/run_test_sequence.py +++ b/captain/utils/test_sequencer/run_test_sequence.py @@ -300,7 +300,7 @@ def _case_test_upload(node: TestNode, hardware_id: str, project_id: str) -> Extr if node.completion_time is None: raise Exception(f"{node.id}: Can't upload a test that wasn't run") if node.export_to_cloud: - cloud = FlojoyCloud(workspace_secret=get_env_var("FLOJOY_CLOUD_KEY")) + cloud = FlojoyCloud(workspace_secret=get_env_var("FLOJOY_CLOUD_WORKSPACE_SECRET")) def reverse_id(test_name) -> str: tests = cloud.get_all_tests_by_project_id(project_id) diff --git a/playwright-test/10_env_modal.spec.ts b/playwright-test/10_env_modal.spec.ts index 466e913b1..396b14932 100644 --- a/playwright-test/10_env_modal.spec.ts +++ b/playwright-test/10_env_modal.spec.ts @@ -58,8 +58,8 @@ test.describe("Environment modal", () => { await window.getByTestId(Selectors.flojoyCloudApiSubmit).click(); try { - // Expect "FLOJOY_CLOUD_KEY" to be listed in the modal - await expect(window.getByText("FLOJOY_CLOUD_KEY")).toBeVisible({ + // Expect "FLOJOY_CLOUD_WORKSPACE_SECRET" to be listed in the modal + await expect(window.getByText("FLOJOY_CLOUD_WORKSPACE_SECRET")).toBeVisible({ timeout: 20000, }); } catch (error) { diff --git a/src/renderer/routes/flow_chart/views/env-var/EnvVarModal.tsx b/src/renderer/routes/flow_chart/views/env-var/EnvVarModal.tsx index 6bf7c3c24..030fb0353 100644 --- a/src/renderer/routes/flow_chart/views/env-var/EnvVarModal.tsx +++ b/src/renderer/routes/flow_chart/views/env-var/EnvVarModal.tsx @@ -100,23 +100,21 @@ const EnvVarModal = () => { const handleSetCloudKey = async () => { if (flojoyCloudKey === "") { - toast("Please enter your Flojoy Cloud API key"); + toast("Please enter your Flojoy Cloud workspace secret"); return; } const res = await postEnvironmentVariable({ - key: "FLOJOY_CLOUD_KEY", + key: "FLOJOY_CLOUD_WORKSPACE_SECRET", value: flojoyCloudKey, }); res.match( () => { - toast( - "Successfully set your Flojoy Cloud API key, let's stream some data to the cloud!", - ); + toast("Successfully set your Flojoy Cloud workspace secret!"); setFlojoyCloudKey(""); fetchCredentials(); }, (e) => { - toast("Error adding your Flojoy Cloud API key", { + toast("Error adding your Flojoy Cloud workspace secret", { description: e.message, }); }, @@ -140,7 +138,7 @@ const EnvVarModal = () => { target="_blank" className="text-sm underline" > - Get your Flojoy Cloud API key + Get your Flojoy Cloud workspace secret (in your workspace settings)
@@ -150,7 +148,7 @@ const EnvVarModal = () => { onChange={(e) => setFlojoyCloudKey(e.target.value)} className="bg-modal" data-testid="flojoy-cloud-api-input" - placeholder="Paste your Flojoy Cloud API key here :)" + placeholder="Paste your Flojoy Cloud workspace secret here :)" />