) => {
setActiveTab(id);
- const tabs = [ ...getTabs() ];
+ const tabs = [...getTabs()];
const tab = tabs.find((tab) => tab.id === id);
const data = tab.data;
+ // TODO: create separate comps for each tab type instead
+ if (tab.type === E_TabType.ENVIRONMENT) {
+ navigate(`/environment/${id}`);
+
+ const aed = getActiveEnvironmentDetails();
+ if (aed === null) {
+ const aed_c: T_ActiveEnvironment = {
+ env_id: id,
+ stage_id: null,
+ };
+ setActiveEnvironmentDetails(aed_c);
+
+ const target_env = getEnvironmentById(id);
+
+ if (target_env) {
+ setActiveEnvironment(target_env);
+ }
+ } else {
+ aed.env_id = id;
+ setActiveEnvironmentDetails(aed);
+
+ if (tab) {
+ if (Object.keys(tab.data).length === 0) {
+ const target_env = getEnvironmentById(id);
+ if (target_env) {
+ setActiveEnvironment(target_env);
+ }
+ } else {
+ setActiveEnvironment(tab.data);
+ }
+ } else {
+ const target_env = getEnvironmentById(id);
+
+ if (target_env) {
+ setActiveEnvironment(target_env);
+ }
+ }
+ }
+
+ // const activeEnvironment = getActiveEnvironmentInEnvironments();
+ // if (activeEnvironment) {
+ // data = structuredClone(activeEnvironment);
+ // // setActiveEnvironment(activeEnvironment);
+ // }
+
+ // setActiveEnvironment(data);
+
+ // setTabData(id, activeEnvironment);
+
+ // setActiveEnvironment(getActiveEnvironmentInEnvironments());
+
+ setActiveTab(id);
+
+ setCurrentSidebarTab(E_SidebarSection.ENVIRONMENT);
+
+ return;
+ }
+
+ navigate(`/http_request/${id}`);
+
let method: T_Method = methods[0];
if (typeof data.method === "string") {
method = methods.find((m) => m.value === data.method) ?? methods[0];
@@ -183,26 +282,43 @@ export default function Tab({ id, status, title, requestType }: I_TabProps) {
data.response_headers,
);
- for(const tab of tabs) {
- if(tab.status === E_TabStatus.SAVED) {
+ // TODO: remove saved state doesn't add anything and makes a lot of UI require a lot of extra logic
+ for (const tab of tabs) {
+ if (tab.status === E_TabStatus.SAVED) {
tab.status = E_TabStatus.NONE;
}
}
+ setCurrentSidebarTab(E_SidebarSection.COLLECTIONS);
+
setTabs(tabs);
}}
{...stylex.props(styles.tab, activeTab === id && styles.active)}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
>
-
- {shortRequestString}
-
+ {/* TODO: add more state details to activeTab */}
+ {tabType === E_TabType.ENVIRONMENT && (
+
+
+
+ )}
+
+ {tabType === E_TabType.HTTP_REQUEST && (
+
+ {shortRequestString}
+
+ )}
{
+ const [envName, setEnvName] = useState(title);
+
+ // const activeEnvironment = useRequestStore((state) => state.activeEnvironment);
+ const getActiveEnvironment = useRequestStore(
+ (state) => state.getActiveEnvironment,
+ );
+ const setTabData = useRequestStore((state) => state.setTabData);
+
+ const setTabState = useRequestStore((state) => state.setTabState);
+
+ // Enabled this if tab should update with input change
+ // TODO: decide if sidebar and tabbar should update with none saved changes
+ // and if sidebar should also show none saved changes status as well :thinking
+ // const setTabTitle = useRequestStore((state) => state.setTabTitle);
+
+ return (
+
+
{
+ setEnvName(e.target.value);
+
+ const ae = getActiveEnvironment();
+ if (ae) {
+ ae.name = e.target.value;
+ // setTabTitle(ae.id, e.target.value);
+ setTabData(ae.id, ae);
+ setTabState(ae.id, E_TabStatus.MODIFIED);
+ }
+ }}
+ onKeyDown={(e: React.KeyboardEvent
) => {
+ if (e.key === "Enter") {
+ // const ns = structuredClone(getCollection());
+ // updateTargetIfExists(ns, getId(), "name", name);
+ // setCollection(ns);
+ // (e.target as HTMLInputElement).blur();
+ }
+ }}
+ />
+
+ {/*
+
+
+
+
|
+
+
+
+
+
+
+
+
+
+
*/}
+
+ );
+};
+
+export interface I_Row {
+ key?: string;
+ value?: string;
+ description?: string;
+}
+
+export default function EnvironmentsPage() {
+ const activeEnvironment = useRequestStore((state) => state.activeEnvironment);
+ const aeRef = useRef(activeEnvironment);
+
+ const addVariableToActiveEnvironment = useRequestStore(
+ (state) => state.addVariableToActiveEnvironment,
+ );
+
+ const getActiveEnvironment = useRequestStore(
+ (state) => state.getActiveEnvironment,
+ );
+ const setTabData = useRequestStore((state) => state.setTabData);
+
+ const setTabState = useRequestStore((state) => state.setTabState);
+
+ const saveActiveEnvironmentAndUpdateEnvironmentsList = useRequestStore(
+ (state) => state.saveActiveEnvironmentAndUpdateEnvironmentsList,
+ );
+
+ useEffect(() => {
+ aeRef.current = activeEnvironment;
+ }, [activeEnvironment]);
+
+ useEffect(() => {
+ SetupShortcuts();
+
+ return () => {
+ CleanUpShortcuts();
+ };
+ }, []);
+
+ async function SetupShortcuts() {
+ // console.log("here");
+
+ addEventListener("keydown", SaveEnvironment);
+ }
+
+ async function CleanUpShortcuts() {
+ removeEventListener("keydown", SaveEnvironment);
+ }
+
+ function SaveEnvironment(e: KeyboardEvent) {
+ if (e.ctrlKey && e.key === "s") {
+ e.preventDefault();
+ if (aeRef.current) {
+ saveActiveEnvironmentAndUpdateEnvironmentsList();
+ // SyncHTTPRequestStateToSidebar();
+ setTabState(aeRef.current.id, E_TabStatus.NONE);
+ }
+ }
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+ {/* */}
+ {/* */}
+
+
+
+
Variable
+
+
+ {/*
+
Type
+ */}
+
+
+
Initial Value
+
+
+
+
Current Value
+
+
+
+ {activeEnvironment?.variables.map((row: T_ManagedVariable) => {
+ return (
+
+ );
+ })}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/pages/environments/params-table-row.tsx b/src/pages/environments/params-table-row.tsx
new file mode 100644
index 0000000..d8b2585
--- /dev/null
+++ b/src/pages/environments/params-table-row.tsx
@@ -0,0 +1,341 @@
+import stylex from "@stylexjs/stylex";
+import { useState } from "react";
+// import DragHandle from "../../../../../assets/drag-handle.svg?react";
+// import { useHover } from "../../../../../hooks/use-hover";
+// import Trashbin from "../../../../../assets/trashbin.svg?react";
+import { Checkbox } from "@controlkit/ui";
+
+import type { ReactNode } from "react";
+import type { T_ManagedVariable } from "@src/stores/request_store/environments_slice";
+import useRequestStore from "@src/stores/request_store";
+import { E_TabStatus } from "@src/stores/request_store/tabbar_slice";
+// import DownArrow from "../../../../../assets/arrow-down.svg?react";
+// import { useOutsideClick } from "../../../../../hooks/use-outside-click";
+
+// TODO: need to parse request contents using environment variable names
+
+const styles = stylex.create({
+ table: {
+ width: "100%",
+ height: "100%",
+
+ //backgroundColor: "gray",
+ },
+
+ headerRow: {
+ display: "grid",
+ gridTemplateColumns: "3rem 1fr 1fr 1fr",
+ alignItems: "center",
+ border: "0.0625rem solid #292929",
+ borderTop: "unset",
+ position: "relative",
+ },
+
+ header: {
+ fontSize: "0.75rem",
+ color: "var(--table-header)",
+ padding: 0,
+ margin: 0,
+ },
+
+ cell: {
+ padding: "0.25rem 0.5rem",
+ display: "flex",
+ alignItems: "center",
+ flexGrow: 1,
+ },
+ borderRightReset: {
+ borderRight: "unset",
+ },
+ borderRight: {
+ borderRight: "0.0625rem solid #292929",
+ },
+
+ dragHandle: {
+ cursor: "pointer",
+ padding: "0.25rem 0.5rem",
+ backgroundColor: {
+ ":hover": "#292929",
+ },
+ },
+
+ input: {
+ margin: "unset",
+ padding: "0.25rem",
+ backgroundColor: "transparent",
+ boxShadow: "unset",
+ border: "unset",
+ outline: "unset",
+ fontSize: "0.75rem",
+ width: "100%",
+ color: "var(--color-text)",
+ },
+
+ trashbin: {
+ cursor: "pointer",
+ padding: "0.25rem",
+ backgroundColor: {
+ ":hover": "#292929",
+ },
+ position: "absolute",
+ right: "0",
+ marginRight: "0.5rem",
+ },
+ hidden: {
+ opacity: 0,
+ pointerEvents: "none",
+ },
+
+ shown: {
+ opacity: 1,
+ pointerEvents: "all",
+ },
+
+ // button: {
+ // backgroundColor: "transparent",
+ // ":hover": {
+ // backgroundColor: "var(--button-hover-color)",
+ // },
+ // alignItems: "start",
+ // display: "flex",
+ // boxShadow: "none",
+ // border: "none",
+ // },
+
+ parent: {
+ position: "relative",
+ width: "100%",
+ },
+
+ button: {
+ backgroundColor: "transparent",
+ cursor: "pointer",
+ gap: "0.5rem",
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ boxShadow: "none",
+ fontSize: "0.75rem",
+ padding: "0rem",
+ width: "100%",
+ border: "transparent",
+ //border: {
+ // ":hover": "transparent",
+ //},
+ },
+
+ menu: {
+ position: "absolute",
+ //padding: "0.5rem",
+ backgroundColor: "#252525",
+ //borderRadius: "0.5rem",
+ width: "100%",
+ marginTop: "0.25rem",
+ display: "flex",
+ flexDirection: "column",
+ boxSizing: "border-box",
+ boxShadow: "0.5rem 0.5rem 0.25rem 0rem rgba(0,0,0,0.75)",
+ fontSize: "0.75rem",
+ zIndex: "1",
+ },
+
+ filled: {
+ backgroundColor: "#252525",
+ },
+
+ pipe: {
+ height: "1rem",
+ flexGrow: 1,
+ borderLeft: "0.0625rem solid #A6A6A6",
+ },
+});
+
+interface I_TableRowProps {
+ envId: string;
+ vr: T_ManagedVariable;
+}
+
+export default function TableRow(props: I_TableRowProps) {
+ // const [variable, setVariable] = useState("");
+ // const [type, setType] = useState("default");
+ // const [initialValue, setInitialValue] = useState("");
+ // const [currentValue, setCurrentValue] = useState("");
+
+ // const [hoverRef, isHovering] = useHover();
+
+ const getActiveEnvironment = useRequestStore(
+ (state) => state.getActiveEnvironment,
+ );
+
+ const updateVariableFieldInActiveEnvironment = useRequestStore(
+ (state) => state.updateVariableFieldInActiveEnvironment,
+ );
+
+ const setTabState = useRequestStore((state) => state.setTabState);
+
+ const setTabData = useRequestStore((state) => state.setTabData);
+
+ return (
+
+
+ {/* */}
+
+ {
+ updateVariableFieldInActiveEnvironment(
+ props.vr.id,
+ "enabled",
+ checked,
+ );
+
+ const ae = getActiveEnvironment();
+ if (ae) {
+ setTabData(props.envId, ae);
+ }
+
+ setTabState(props.envId, E_TabStatus.MODIFIED);
+ }}
+ />
+
+
+
+ {
+ updateVariableFieldInActiveEnvironment(
+ props.vr.id,
+ "key",
+ event.target.value,
+ );
+
+ const ae = getActiveEnvironment();
+ if (ae) {
+ setTabData(props.envId, ae);
+ }
+
+ setTabState(props.envId, E_TabStatus.MODIFIED);
+ }}
+ value={props.vr.key}
+ placeholder="Variable"
+ />
+
+
+ {/*
+
+
+
+
+
*/}
+
+
+ {
+ updateVariableFieldInActiveEnvironment(
+ props.vr.id,
+ "initial_value",
+ event.target.value,
+ );
+
+ const ae = getActiveEnvironment();
+ if (ae) {
+ setTabData(props.envId, ae);
+ }
+
+ setTabState(props.envId, E_TabStatus.MODIFIED);
+ }}
+ value={props.vr.initial_value}
+ placeholder="Initial Value"
+ />
+
+
+
+ {
+ updateVariableFieldInActiveEnvironment(
+ props.vr.id,
+ "current_value",
+ event.target.value,
+ );
+
+ const ae = getActiveEnvironment();
+ if(ae) {
+ setTabData(props.envId, ae);
+ }
+
+ setTabState(props.envId, E_TabStatus.MODIFIED);
+ }}
+ value={props.vr.current_value}
+ placeholder="Current Value"
+ />
+
+
+ {/*
*/}
+
+ );
+}
+
+// TODO: Check with aaron what he did with this stuff
+interface I_TypeValueDropdownProps {
+ children?: ReactNode;
+ title: string;
+ variant?: "filled";
+}
+
+export function TypeValueDropdown({
+ children,
+ title,
+ variant,
+}: I_TypeValueDropdownProps) {
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
+ // const modalRef = useOutsideClick(() => setIsMenuOpen(!isMenuOpen));
+
+ return (
+
+
+
+ {isMenuOpen && (
+
+ {children}
+
+ )}
+
+ );
+}
diff --git a/src/pages/http_requests/request-row/index.tsx b/src/pages/http_requests/request-row/index.tsx
index d52e227..3e7d107 100644
--- a/src/pages/http_requests/request-row/index.tsx
+++ b/src/pages/http_requests/request-row/index.tsx
@@ -10,11 +10,11 @@ import { RequestRowUrlInput } from "./components/request-row-url-input.tsx";
// import SaveSVG from "@assets/save.svg?react";
// import React from "react";
-// import { invoke } from "@tauri-apps/api/core";
-import { Button, Input, Label } from "@controlkit/ui";
+import { Input, Label } from "@controlkit/ui";
import useRequestStore from "@src/stores/request_store";
import { updateTargetIfExists } from "@src/stores/request_store/sidebar_slice.ts";
import { E_TabStatus } from "@src/stores/request_store/tabbar_slice.ts";
+import SendRequestBtn from "./send_request.tsx";
// import { useSetRecoilState } from 'recoil';
// import { HTTP_API_Response_Body_StateData } from "@store/http-api-request-and-response/response-body.ts";
@@ -94,7 +94,6 @@ interface RequestRowProps {
// @ts-ignore
export function RequestRow(props: RequestRowProps) {
- const sendRequest = useRequestStore((state) => state.sendRequest);
const name = useRequestStore((state) => state.name);
const setName = useRequestStore((state) => state.setName);
@@ -204,13 +203,7 @@ export function RequestRow(props: RequestRowProps) {
-
+
{/* (
diff --git a/src/pages/http_requests/request-row/send_request.tsx b/src/pages/http_requests/request-row/send_request.tsx
new file mode 100644
index 0000000..2293a28
--- /dev/null
+++ b/src/pages/http_requests/request-row/send_request.tsx
@@ -0,0 +1,156 @@
+import { Button } from "@controlkit/ui";
+import useRequestStore from "@src/stores/request_store";
+import type { T_Header } from "@src/stores/request_store/request_slice";
+import { invoke } from "@tauri-apps/api/core";
+
+export default function SendRequestBtn() {
+ // const sendRequest = useRequestStore((state) => state.sendRequest);
+
+ const getHTTPRequest = useRequestStore((state) => state.getHTTPRequest);
+ const getEnabledEnvironmentAndDetails = useRequestStore(
+ (state) => state.getEnabledEnvironmentAndDetails,
+ );
+
+ const setLoading = useRequestStore((state) => state.setLoading);
+ const setResponse = useRequestStore((state) => state.setResponse);
+ const setResponseHeaders = useRequestStore((state) => state.setResponseHeaders);
+ const setResponseCookies = useRequestStore((state) => state.setResponseCookies);
+
+ function ReplaceManagedVariable(env: any, sub_target: any): string {
+ console.log(env.variables);
+
+ let s = sub_target;
+ for(const variable of env.variables) {
+ console.log("VAR - ", s, variable.key, variable.initial_value, variable.current_value);
+
+ if(variable.current_value !== "") {
+ if(variable.current_value === "NULL") {
+ s = s.replace(`{{${variable.key}}}`, "null");
+ continue;
+ }
+
+ s = s.replace(`{{${variable.key}}}`, variable.current_value);
+ }
+
+ if(variable.initial_value !== "") {
+ if(variable.initial_value === "NULL") {
+ s = s.replace(`{{${variable.key}}}`, "null");
+ continue;
+ }
+
+ s = s.replace(`{{${variable.key}}}`, variable.initial_value);
+ }
+
+ // console.log(s.replace(`{{${variable.key}}}`, variable.value));
+ // s = s.replace(`{{${variable.key}}}`, variable.value);
+ }
+
+ return s;
+ }
+
+ function AttemptToSendHTTPRequest() {
+ setLoading(true);
+
+ const { url, method, autoHeaders, headers, body, cookies } =
+ getHTTPRequest();
+
+ // const method = get().method;
+ // const s = get();
+ // const { url, body, cookies, autoHeaders, headers } = get();
+
+ // set({ loading: true, error: null });
+
+ console.group("AttemptToSendHTTPRequest");
+ console.log("METHOD - ", method);
+ console.log("URL - ", url);
+ console.log("AUTO HEADERS - ", autoHeaders);
+ console.log("HEADERS - ", headers);
+ console.log("BODY - ", body);
+ console.log("COOKIES - ", cookies);
+
+ // TODO: verify data before invoking
+ // console.log(url);
+ const trimmedUrl = url.trim();
+ if (trimmedUrl.length === 0) {
+ // TODO: error state ui
+ // set({ error: "URL cannot be empty", loading: false });
+ return;
+ }
+
+ const env = getEnabledEnvironmentAndDetails();
+
+ console.log("ENV - ", env);
+
+ // url
+ // body
+ // headers
+
+ // get().environments();
+
+ // console.log(trimmedUrl);
+
+ console.log("SUBBED");
+
+ let subbed_url = trimmedUrl;
+ let subbed_body = body;
+ let subbed_headers = structuredClone(headers);
+
+ subbed_url = ReplaceManagedVariable(env, subbed_url);
+ subbed_body = ReplaceManagedVariable(env, subbed_body);
+ for(let idx = 0; idx < subbed_headers.length; ++idx) {
+ subbed_headers[idx].value = ReplaceManagedVariable(env, subbed_headers[idx].value);
+ }
+
+ const filtered_headers = subbed_headers
+ .filter((h: T_Header) => h.enabled)
+ .map((h: T_Header) => `${h.key}: ${h.value}`)
+ .join(", ");
+
+ console.log("METHOD - ", method);
+ console.log("URL - ", subbed_url);
+ console.log("AUTO HEADERS - ", autoHeaders);
+ console.log("HEADERS - ", subbed_headers);
+ console.log("FILTERED HEADERS - ", filtered_headers);
+ console.log("BODY - ", subbed_body);
+ console.log("COOKIES - ", cookies);
+
+ invoke("http_request", {
+ method: method.value,
+ headers: filtered_headers,
+ url: subbed_url,
+ body: subbed_body,
+ cookies: "",
+ })
+ // biome-ignore lint/suspicious/noExplicitAny:
+ .then((message: any) => {
+ console.log(message);
+
+ setResponse(message.response_data_string);
+ setResponseHeaders(message.response_headers);
+ setResponseCookies(message.response_cookies);
+ setLoading(false);
+
+ // setResponse(message.response_data_string);
+ // set_HTTP_API_Response_Body(message.response_data_string);
+ // set_HTTP_API_Response_Headers(message.response_headers);
+ })
+ .catch((error_message) => {
+ console.error(error_message);
+
+ setLoading(false);
+ });
+
+ console.groupEnd();
+ }
+
+ return (
+
+ );
+}
diff --git a/src/pages/http_requests/response/index.tsx b/src/pages/http_requests/response/index.tsx
index c8c6306..7b26f66 100644
--- a/src/pages/http_requests/response/index.tsx
+++ b/src/pages/http_requests/response/index.tsx
@@ -171,7 +171,7 @@ function ResponseSection() {
return;
}
- if (size > body.clientHeight - 38 - 20) {
+ if (size > body.clientHeight - 38 - 20 - 30) {
// navbar - tab bar - borders
return;
}
@@ -195,7 +195,11 @@ function ResponseSection() {
// children={undefined}
hideRightSegment={false}
>
-
+
{response === null ? (
<>
{no_res_tabs.map((tab, index) => {
diff --git a/src/stores/request_store/environments_slice.ts b/src/stores/request_store/environments_slice.ts
new file mode 100644
index 0000000..e37ddb9
--- /dev/null
+++ b/src/stores/request_store/environments_slice.ts
@@ -0,0 +1,396 @@
+import type { StateCreator } from "zustand";
+// TODO: replace with uuid v7 when possible
+import { v4 as uuidv4 } from "uuid";
+
+export type T_ActiveEnvironmentSliceItem =
+ | "GLOBAL"
+ | "VAULT"
+ | "ENVIRONMENT"
+ | null;
+
+export type T_ActiveEnvironment = {
+ env_id: string | null;
+ stage_id: string | null;
+};
+
+export type T_ManagedVariable = {
+ id: string;
+ key: string;
+ description: string;
+ enabled: boolean;
+ secret: boolean;
+ initial_value: string;
+ current_value: string;
+};
+
+export type T_EnvironmentStageVariable = {
+ id: string;
+ value: string;
+};
+
+export type T_EnvironmentStage = {
+ id: string;
+ env_id: string;
+ name: string;
+ description: string;
+
+ variables: T_EnvironmentStageVariable[];
+};
+
+export type T_Environment = {
+ id: string;
+ name: string;
+
+ variables: T_ManagedVariable[];
+ stages: T_EnvironmentStage[];
+};
+
+export interface EnvironmentsSlice {
+ activeEnvironmentSliceItem: T_ActiveEnvironmentSliceItem;
+ setActiveEnvironmentSliceItem: (item: T_ActiveEnvironmentSliceItem) => void;
+ getActiveEnvironmentSliceItem: () => T_ActiveEnvironmentSliceItem;
+
+ enabledEnvironment: T_ActiveEnvironment | null;
+ setEnabledEnvironmentDetails: (
+ environment_id: T_ActiveEnvironment | null,
+ ) => void;
+ getEnabledEnvironmentDetails: () => T_ActiveEnvironment | null;
+ getEnabledEnvironmentAndDetails: () => T_ActiveEnvironment & T_Environment | null;
+
+ // TODO: rename this to something better emabled is the environment to pull variables from
+ // active is for the tabs sidebar and active page edit
+ activeEnvironmentDetails: T_ActiveEnvironment | null;
+ setActiveEnvironmentDetails: (
+ environment_id: T_ActiveEnvironment | null,
+ ) => void;
+ getActiveEnvironmentDetails: () => T_ActiveEnvironment | null;
+
+ activeEnvironment: T_Environment | null;
+ setActiveEnvironment: (environment_id: T_Environment) => void;
+ getActiveEnvironment: () => T_Environment | null;
+ setActiveEnvironmentInEnvironments: (environment_id: T_Environment) => void;
+ getActiveEnvironmentInEnvironments: () => T_Environment | null;
+ addVariableToActiveEnvironment: () => void;
+ updateVariableFieldInActiveEnvironment: (
+ variable_id: string,
+ field: string,
+ value: string | boolean,
+ ) => void;
+ saveActiveEnvironmentAndUpdateEnvironmentsList: () => void;
+
+ // HELPERS
+
+ // TODO: separate out different environments data object will certainly grow too large
+ // TODO: use immer for state update slices
+ environments: T_Environment[];
+ setEnvironments: (collection: T_Environment[]) => void;
+ getEnvironments: () => T_Environment[];
+ addEmptyDefaultEnvironment: () => void;
+
+ getEnvironmentById: (id: string) => T_Environment | null;
+
+ globals: T_ManagedVariable[];
+ setGlobals: (collection: T_ManagedVariable[]) => void;
+ getGlobals: () => T_ManagedVariable[];
+
+ vault: T_ManagedVariable[];
+ setVault: (vault_items: T_ManagedVariable[]) => void;
+ getVault: () => T_ManagedVariable[];
+
+ vaultSecret: string | null;
+ setVaultSecret: (secret: string | null) => void;
+ getVaultSecret: () => string | null;
+}
+
+export const createEnvironmentsSlice: StateCreator<
+ EnvironmentsSlice,
+ [],
+ [],
+ EnvironmentsSlice
+> = (set, get) => ({
+ activeEnvironmentSliceItem: null,
+ setActiveEnvironmentSliceItem: (item: T_ActiveEnvironmentSliceItem) =>
+ set({ activeEnvironmentSliceItem: item }),
+ getActiveEnvironmentSliceItem: () => get().activeEnvironmentSliceItem,
+
+ enabledEnvironment: null,
+ setEnabledEnvironmentDetails: (
+ environment_details: T_ActiveEnvironment | null,
+ ) => {
+ set({ enabledEnvironment: environment_details });
+ },
+ getEnabledEnvironmentDetails: () => get().enabledEnvironment,
+ getEnabledEnvironmentAndDetails: () => {
+ const ee = get().enabledEnvironment;
+ if(ee === null) return null;
+
+ const env = get().environments.find(
+ (env) => env.id === get().enabledEnvironment?.env_id,
+ );
+ if(env == null) return null;
+
+ return {
+ ...ee,
+ ...env,
+ };
+ },
+
+ activeEnvironmentDetails: null,
+ setActiveEnvironmentDetails: (environment_id: T_ActiveEnvironment | null) =>
+ set({ activeEnvironmentDetails: environment_id }),
+ getActiveEnvironmentDetails: () => get().activeEnvironmentDetails,
+
+ activeEnvironment: null,
+ setActiveEnvironment: (environment: T_Environment) => {
+ set({
+ activeEnvironment: environment,
+ });
+ },
+ getActiveEnvironment: () => get().activeEnvironment,
+
+ setActiveEnvironmentInEnvironments: (environment: T_Environment) => {
+ const envs = structuredClone(get().environments);
+
+ const env_index = envs.findIndex((env) => env.id === environment.id);
+ if (env_index) {
+ envs[env_index] = structuredClone(environment);
+
+ set({
+ environments: envs,
+ });
+ }
+ },
+ getActiveEnvironmentInEnvironments: () => {
+ return (
+ get().environments.find(
+ (env) => env.id === get().activeEnvironmentDetails?.env_id,
+ ) || null
+ );
+ },
+ addVariableToActiveEnvironment: () => {
+ const aenv = get().activeEnvironment;
+
+ if (aenv) {
+ const managed_var_empty: T_ManagedVariable = {
+ id: uuidv4(),
+ key: "",
+ description: "",
+ enabled: true,
+ secret: false,
+ initial_value: "",
+ current_value: "",
+ };
+
+ aenv.variables.push(managed_var_empty);
+
+ set({
+ activeEnvironment: structuredClone(aenv),
+ });
+ }
+ },
+ updateVariableFieldInActiveEnvironment: (
+ variable_id: string,
+ field: string,
+ value: string | boolean,
+ ) => {
+ const aenv = get().activeEnvironment;
+
+ if (aenv) {
+ const var_index = aenv.variables.findIndex((v) => v.id === variable_id);
+ if (var_index !== -1) {
+ // @ts-ignore
+ aenv.variables[var_index][field] = value;
+
+ set({
+ activeEnvironment: structuredClone(aenv),
+ });
+ }
+ }
+ },
+ saveActiveEnvironmentAndUpdateEnvironmentsList: () => {
+ const aenv = get().activeEnvironment;
+
+ if (aenv) {
+ const envs = structuredClone(get().environments);
+
+ const env_index = envs.findIndex((env) => env.id === aenv.id);
+
+ if (env_index !== -1) {
+ envs[env_index] = structuredClone(aenv);
+
+ set({
+ environments: envs,
+ });
+ }
+ }
+ },
+
+ environments: [], // environment_test_data,
+ setEnvironments: (environments) => set({ environments }),
+ getEnvironments: () => get().environments,
+ addEmptyDefaultEnvironment: () => {
+ const envs = structuredClone(get().environments);
+
+ const new_env: T_Environment = {
+ id: uuidv4(),
+ name: "New Environment",
+ variables: [],
+ stages: [],
+ };
+
+ envs.push(new_env);
+
+ set({
+ environments: envs,
+ });
+ },
+
+ getEnvironmentById: (id: string) => {
+ return get().environments.find((env) => env.id === id) || null;
+ },
+
+ globals: [], // globals_test_data,
+ setGlobals: (globals) => set({ globals }),
+ getGlobals: () => get().globals,
+
+ // TODO: vault and secret mangement - stronghold or other secure storage requied for secret - prereq
+ vault: [],
+ setVault: (vault_items) => set({ vault: vault_items }),
+ getVault: () => get().vault,
+
+ vaultSecret: null,
+ setVaultSecret: (secret) => set({ vaultSecret: secret }),
+ getVaultSecret: () => get().vaultSecret,
+});
+
+/*
+const env_id = uuidv4();
+const v1 = uuidv4();
+const v2 = uuidv4();
+const v3 = uuidv4();
+
+const _globals_test_data: T_ManagedVariable[] = [
+ {
+ id: v1,
+ key: "access_token",
+ description: "jwt access token",
+ enabled: true,
+ secret: false,
+ initial_value: "default value",
+ current_value: "",
+ },
+
+ {
+ id: v2,
+ key: "refresh_token",
+ description: "jwt refresh token",
+ // TODO: if a disabled variable is used in a request, show user a prompt warning with the specific variable.
+ enabled: false,
+ secret: false,
+ // TODO: UI - if a stage active, dim none active stage and default values
+ initial_value: "default value",
+ current_value: "",
+ },
+
+ {
+ id: v3,
+ key: "secret_var",
+ description: "hidden secret for UI testing",
+ enabled: true,
+ secret: true,
+ initial_value: "default value",
+ current_value: "",
+ },
+];
+
+const _environment_test_data: T_Environment[] = [
+ {
+ id: env_id,
+ name: "1 - New Environment",
+
+ variables: [
+ {
+ id: v1,
+ key: "access_token",
+ description: "jwt access token",
+ enabled: true,
+ secret: false,
+ initial_value: "default value",
+ current_value: "",
+ },
+
+ {
+ id: v2,
+ key: "refresh_token",
+ description: "jwt refresh token",
+ // TODO: if a disabled variable is used in a request, show user a prompt warning with the specific variable.
+ enabled: false,
+ secret: false,
+ // TODO: UI - if a stage active, dim none active stage and default values
+ initial_value: "default value",
+ current_value: "",
+ },
+
+ {
+ id: v3,
+ key: "secret_var",
+ description: "hidden secret for UI testing",
+ enabled: true,
+ secret: true,
+ initial_value: "default value",
+ current_value: "",
+ },
+ ],
+
+ stages: [
+ {
+ id: uuidv4(),
+ env_id: env_id,
+ name: "dev",
+ description: "development stage",
+
+ variables: [
+ {
+ id: v1,
+ value: "access",
+ },
+
+ {
+ id: v2,
+ value: "refresh",
+ },
+
+ {
+ id: v3,
+ value: "secret value",
+ },
+ ],
+ },
+
+ {
+ id: uuidv4(),
+ env_id: env_id,
+ name: "prod",
+ description: "live / production",
+
+ variables: [
+ {
+ id: v1,
+ value: "prod-access",
+ },
+
+ {
+ id: v2,
+ value: "prod-refresh",
+ },
+
+ {
+ id: v3,
+ value: "prod secret value",
+ },
+ ],
+ },
+ ],
+ },
+];
+*/
\ No newline at end of file
diff --git a/src/stores/request_store/index.ts b/src/stores/request_store/index.ts
index dbfb944..7519f0c 100644
--- a/src/stores/request_store/index.ts
+++ b/src/stores/request_store/index.ts
@@ -2,11 +2,13 @@ import { create } from "zustand";
import { createRequestSlice, type RequestSlice } from "./request_slice";
import { createSidebarSlice, type SidebarSlice } from "./sidebar_slice";
import { createTabbarSlice, type TabbarSlice } from "./tabbar_slice";
+import { createEnvironmentsSlice, type EnvironmentsSlice } from "./environments_slice";
-const useRequestStore = create()((...a) => ({
+const useRequestStore = create()((...a) => ({
...createRequestSlice(...a),
...createSidebarSlice(...a),
...createTabbarSlice(...a),
+ ...createEnvironmentsSlice(...a),
}));
export default useRequestStore;
diff --git a/src/stores/request_store/request_slice.ts b/src/stores/request_store/request_slice.ts
index 0ea1a70..d064727 100644
--- a/src/stores/request_store/request_slice.ts
+++ b/src/stores/request_store/request_slice.ts
@@ -192,12 +192,18 @@ export interface RequestSlice {
setCookies: (cookies: Record) => void;
response: any;
+ setResponse: (response: any) => void;
response_headers: any;
+ setResponseHeaders: (response: any) => void;
response_cookies: any;
+ setResponseCookies: (response: any) => void;
loading: boolean;
+ setLoading: (arg: boolean) => void;
error: string | null;
sendRequest: () => Promise;
+ getHTTPRequest: () => any;
+
setRequestParameters: (
id: string,
name: string,
@@ -322,10 +328,22 @@ export const createRequestSlice: StateCreator<
setCookies: (cookies) => set({ cookies }),
response: null,
+ setResponse: (response: any) => {
+ set({ response: response });
+ },
response_headers: null,
+ setResponseHeaders: (headers: any) => {
+ set({ response_headers: headers });
+ },
response_cookies: null,
+ setResponseCookies: (cookies: any) => {
+ set({ response_cookies: cookies });
+ },
loading: false,
+ setLoading: (arg: boolean) => set({ loading: arg }),
error: null,
+
+ // TODO: old clean
sendRequest: async () => {
set({ loading: true });
@@ -350,8 +368,12 @@ export const createRequestSlice: StateCreator<
// set({ error: "URL cannot be empty", loading: false });
return;
}
- // console.log(trimmedUrl);
- // return;
+
+ // url
+ // body
+ // headers
+
+ console.log(trimmedUrl);
invoke("http_request", {
method: method.value,
@@ -397,6 +419,17 @@ export const createRequestSlice: StateCreator<
// }
},
+ getHTTPRequest: () => {
+ return {
+ url: get().url,
+ method: get().method,
+ autoHeaders: get().autoHeaders,
+ headers: get().headers,
+ body: get().body,
+ cookies: get().cookies,
+ };
+ },
+
setRequestParameters: (
id: string,
name: string,
diff --git a/src/stores/request_store/sidebar_slice.ts b/src/stores/request_store/sidebar_slice.ts
index 2399846..36253f6 100644
--- a/src/stores/request_store/sidebar_slice.ts
+++ b/src/stores/request_store/sidebar_slice.ts
@@ -2,7 +2,21 @@ import type { StateCreator } from "zustand";
import { v4 as uuidv4 } from "uuid";
import type { T_Header, T_Method } from "./request_slice";
+export enum E_SidebarSection {
+ HOME = "HOME",
+ COLLECTIONS = "COLLECTIONS",
+ CONNECTED = "CONNECTED",
+ DB = "DB",
+ ENVIRONMENT = "ENVIRONMENT",
+ HISTORY = "HISTORY",
+ NOTE = "NOTE",
+ TREND = "TREND",
+}
+
export interface SidebarSlice {
+ currentSidebarTab: E_SidebarSection | null;
+ setCurrentSidebarTab: (tab: E_SidebarSection | null) => void;
+
// biome-ignore lint/suspicious/noExplicitAny:
collection: any[];
// biome-ignore lint/suspicious/noExplicitAny:
@@ -22,6 +36,11 @@ export const createSidebarSlice: StateCreator<
[],
SidebarSlice
> = (set, get) => ({
+ currentSidebarTab: E_SidebarSection.COLLECTIONS,
+ setCurrentSidebarTab: (tab: E_SidebarSection | null) => {
+ set({ currentSidebarTab: tab });
+ },
+
collection: [], // test_data,
setCollection: (collection) => set({ collection }),
getCollection: () => get().collection,
@@ -150,7 +169,12 @@ function addToTargetIfExists(nc: any, id: string, value: any) {
}
}
-export function updateTargetIfExists(nc: any, id: string, field: string, value: any) {
+export function updateTargetIfExists(
+ nc: any,
+ id: string,
+ field: string,
+ value: any,
+) {
for (let i = 0; i < nc.length; ++i) {
// console.log("NC", nc[i].id);
diff --git a/src/stores/request_store/tabbar_slice.ts b/src/stores/request_store/tabbar_slice.ts
index 00ed280..dcb5fc6 100644
--- a/src/stores/request_store/tabbar_slice.ts
+++ b/src/stores/request_store/tabbar_slice.ts
@@ -13,6 +13,7 @@ export type T_Tab = {
export enum E_TabType {
HTTP_REQUEST = "HTTP_REQUEST",
+ ENVIRONMENT = "ENVIRONMENT",
};
export enum E_TabStatus {
@@ -28,12 +29,18 @@ export interface TabbarSlice {
setTabs: (collection: any[]) => void;
getTabs: () => any[];
+ getActiveTab: () => T_Tab | null;
+
activeTab: string | null;
setActiveTab: (tab_id: string | null) => void;
+ setTabTitle: (tab_id: string, title: string) => void;
+
setTabState: (tab_id: string, state: E_TabStatus) => void;
setTabDataField: (tab_id: string, field: string, value: any) => void;
+
+ setTabData: (tab_id: string, data: any) => void;
}
export const createTabbarSlice: StateCreator<
@@ -49,6 +56,24 @@ export const createTabbarSlice: StateCreator<
activeTab: null,
setActiveTab: (tab_id) => set({ activeTab: tab_id }),
+ getActiveTab: () => {
+ const tab_id = get().activeTab;
+ const tabs = get().tabs;
+
+ return tabs.find((tab) => tab.id === tab_id) ?? null;
+ },
+
+ setTabTitle: (tab_id: string, title: string) => {
+ const tabs = [ ...get().tabs ];
+ const tab = tabs.find((tab) => tab.id === tab_id);
+
+ if (tab) {
+ tab.title = title;
+ }
+
+ set({ tabs });
+ },
+
setTabState: (tab_id: string, state: E_TabStatus) => {
const tabs = [ ...get().tabs ];
const tab = tabs.find((tab) => tab.id === tab_id);
@@ -70,6 +95,17 @@ export const createTabbarSlice: StateCreator<
set({ tabs });
},
+
+ setTabData: (tab_id: string, data: any) => {
+ const tabs = [ ...get().tabs ];
+ const tab = tabs.find((tab) => tab.id === tab_id);
+
+ if (tab) {
+ tab.data = data;
+ }
+
+ set({ tabs });
+ },
});
export const test_data: T_Tab[] = [