Skip to content

Commit

Permalink
more store actions and closer to a RC
Browse files Browse the repository at this point in the history
  • Loading branch information
khill-fbmc committed Oct 21, 2024
1 parent a34edfb commit 808cd79
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 47 deletions.
32 changes: 26 additions & 6 deletions src/hooks/useStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ export type State = {
workflow: {
id: string;
apiKey: string;
enabled: boolean;
};
apps: RetoolApp[];
};

export type Actions = {
reset: () => void;
addApp: (app: RetoolApp) => void;
createApp: (namr: RetoolApp["name"]) => void;
removeApp: (name: RetoolApp["name"]) => void;
updateApp: (name: RetoolApp["name"], props: Partial<RetoolApp>) => void;
updateActiveApp: (props: Partial<RetoolApp>) => void;
Expand All @@ -33,6 +35,8 @@ export type Actions = {
setEditMode: (state: boolean) => void;
setActiveTab: (tab: TabKeys) => void;
updateWorkflow: (workflow: Partial<State["workflow"]>) => void;
getRetoolWorkflowUrl: () => string;
toggleWorkflowProvider: () => void;
};

export const STORAGE_KEY = "app-embedder-for-retool4";
Expand All @@ -45,6 +49,7 @@ const initialState: State = {
workflow: {
id: "13d34554-9891-40c0-a032-fda523774e97",
apiKey: "retool_wk_bde9d74b27644cf3a0691211ff18dee2",
enabled: false,
},
apps: [INSPECTOR_APP, ...DEMO_APPS],
};
Expand All @@ -58,6 +63,17 @@ export const useStore = create<State & Actions>()(
setDomain: (domain) => set(() => ({ domain })),
setEditMode: (isEditing) => set(() => ({ isEditing })),
addApp: (app) => set((state) => ({ apps: [...state.apps, app] })),
createApp: (name: RetoolApp["name"]) => {
get().addApp({
name,
public: false,
version: "latest",
env: "development",
hash: [],
query: [],
});
get().setActiveApp(name);
},
removeApp: (name) => {
set((state) => ({
apps: state.apps.filter((app) => app.name !== name),
Expand All @@ -71,24 +87,28 @@ export const useStore = create<State & Actions>()(
}));
},
getActiveApp: () => {
const activeAppName = get().activeAppName;
return get().apps.find((app) => app.name === activeAppName);
const { activeAppName, apps } = get();
return apps.find((app) => app.name === activeAppName);
},
setActiveApp: (name) => {
set(() => ({ activeAppName: name }));
},
updateActiveApp: (props) => {
const name = get().activeAppName;
if (name) {
get().updateApp(name, props);
}
const { activeAppName, updateApp } = get();
if (activeAppName) updateApp(activeAppName, props);
},
updateWorkflow: (props) => {
set((state) => ({
...state,
workflow: { ...state.workflow, ...props },
}));
},
getRetoolWorkflowUrl: () => {
return `https://${get().domain}.retool.com/workflows/${get().workflow.id}`;
},
toggleWorkflowProvider: () => {
get().updateWorkflow({ enabled: !get().workflow.enabled });
},
}),
{
name: STORAGE_KEY,
Expand Down
17 changes: 17 additions & 0 deletions src/hooks/useStorePrimitives.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useStore } from "@/hooks/useStore";

import type { State } from "@/hooks/useStore";

export function useStorePrimitives() {
const _state = useStore();
let state: Partial<State> = {};

for (const [k, v] of Object.entries(_state)) {
const key = k as keyof State;
if (typeof _state[key] !== "function") {
state = { ...state, [key]: v };
}
}

return state;
}
8 changes: 4 additions & 4 deletions src/pages/Options/Tabs/JSONTab.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from "react";
import { Card, Col, Row } from "react-bootstrap";
import { Card } from "react-bootstrap";
import Container from "react-bootstrap/Container";

import { useStore } from "@/hooks/useStore";
import { useStorePrimitives } from "@/hooks/useStorePrimitives";

import { SimpleJsonView } from "../components/SimpleJsonView";

function JSONTab() {
const state = useStore();
console.log(state);
const state = useStorePrimitives();

return (
<Container className="pb-5">
<div className="d-flex flex-column align-items-center">
Expand Down
95 changes: 95 additions & 0 deletions src/pages/Options/Tabs/SettingsTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React from "react";
import { Alert, Button, Col, Container, Row } from "react-bootstrap";
import { FormProvider, type SubmitHandler, useForm } from "react-hook-form";

import { useEditMode } from "@/hooks/useEditMode";
import { useStore } from "@/hooks/useStore";
import { successToast } from "@/lib/toast";

import AppCard from "../components/AppCard";
import AppForm from "../components/AppForm";
import DomainInput from "../components/DomainInput";

import type { RetoolApp } from "@/types/extension";

function ConfigTab() {
const methods = useForm<RetoolApp>();
const setActiveTab = useStore((s) => s.setActiveTab);
const { isEditing, startEditMode, stopEditMode } = useEditMode();

const createApp = useStore((s) => s.createApp);
const getActiveApp = useStore((s) => s.getActiveApp);
const activeAppName = useStore((s) => s.activeAppName);
const updateActiveApp = useStore((s) => s.updateActiveApp);

const createNewApp = () => {
startEditMode();
createApp("new-app-1");
};

const onSave: SubmitHandler<RetoolApp> = (data) => {
updateActiveApp(data);
successToast("Edits saved.");
stopEditMode();
};

const onCancel = () => {
methods.reset();
stopEditMode();
};

const app = getActiveApp();

return (
<>
<Row className="mt-2">
<Col lg={{ offset: 2, span: 8 }} sm={{ offset: 1, span: 10 }} xs={12}>
<h3>General Config</h3>
<DomainInput />

<h3 className="mt-2">Current App</h3>
{isEditing ? (
<FormProvider {...methods}>
<AppForm app={app!} onSave={onSave} onCancel={onCancel} />
</FormProvider>
) : (
<Container className="pt-2">
{activeAppName ? (
<AppCard
isActive
editable
app={app}
onEdit={() => startEditMode()}
/>
) : (
<Alert variant="warning">
<Alert.Heading>None Selected</Alert.Heading>
To view your app list{" "}
<Alert.Link
href="#"
onClick={(e) => {
e.preventDefault();
setActiveTab("storage");
}}
>
click here
</Alert.Link>
.
</Alert>
)}
</Container>
)}
</Col>
</Row>
{!isEditing && (
<div className="d-flex mt-5">
<Button variant="success" className="mx-auto" onClick={createNewApp}>
Create New
</Button>
</div>
)}
</>
);
}

export default ConfigTab;
51 changes: 33 additions & 18 deletions src/pages/Options/Tabs/WorkflowTab.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect } from "react";
import { Alert, Col, Row } from "react-bootstrap";
import Button from "react-bootstrap/Button";
import Card from "react-bootstrap/Card";
Expand All @@ -11,42 +11,57 @@ import { useWorkflowData } from "@/hooks/useWorkflow";
import { SimpleJsonView } from "../components/SimpleJsonView";

function WorkflowTab() {
const [useProvider, setUseProvider] = useState(false);
const {
apiKey,
id: workflowId,
enabled: workflowEnabled,
} = useStore((s) => s.workflow);

const { apiKey, id: workflowId } = useStore((s) => s.workflow);
const updateWorkflow = useStore((s) => s.updateWorkflow);
const retoolWorkflowUrl = useStore((s) => s.getRetoolWorkflowUrl);
const toggleWorkflowProvider = useStore((s) => s.toggleWorkflowProvider);

const { workflow, fetchWorkflowData } = useWorkflowData(apiKey, workflowId);

useEffect(() => {
if (useProvider && workflowId && apiKey) {
if (workflowEnabled && workflowId && apiKey) {
fetchWorkflowData();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [useProvider, workflow]);
}, [workflowEnabled, workflowId, apiKey]);

return (
<Container>
<div className="my-2 d-flex">
<h2 className="mx-auto">Remote Apps List</h2>
<h2 className="mx-auto">Workflow Provider</h2>
</div>

<Row>
<Col className="offset-1 col-10">
<Alert variant="warning">
<Alert.Heading>How To Use</Alert.Heading>
Here are all your saved Retool App Definitions
Use the workflow provider to add more apps to your list, from
Retool!
</Alert>
</Col>
</Row>

<Row>
<Col>
<Card className="shadow">
<Card.Header>
<Card.Header className="d-inline-flex justify-content-between">
<div className="d-flex gap-2">
<i className="bi bi-cloud"></i>
Workflow Details
Workflow
</div>
<a
className="d-flex gap-2 link-secondary"
href={retoolWorkflowUrl()}
target="_blank"
rel="noreferrer"
>
View in Retool<i className="bi bi-box-arrow-up-right"></i>
</a>
</Card.Header>
<Card.Body>
<Form.Group className="mb-4" controlId="workflowUrl">
Expand All @@ -57,7 +72,7 @@ function WorkflowTab() {
<Form.Label>Workflow ID</Form.Label>
<Form.Control
value={workflowId}
disabled={!useProvider}
disabled={workflowEnabled === false}
onChange={(e) => updateWorkflow({ id: e.target.value })}
/>
<Form.Text className="text-muted">
Expand All @@ -70,7 +85,7 @@ function WorkflowTab() {
<Form.Control
type="password"
value={apiKey}
disabled={!useProvider}
disabled={workflowEnabled === false}
onChange={(e) => updateWorkflow({ apiKey: e.target.value })}
/>
<Form.Text className="text-muted">
Expand All @@ -81,15 +96,15 @@ function WorkflowTab() {
<Card.Footer>
<div className="d-flex justify-content-between">
<Button
variant={useProvider ? "warning" : "primary"}
variant={workflowEnabled ? "warning" : "primary"}
title={`Enable using a workflow to provide the app name list`}
onClick={() => setUseProvider((old) => !old)}
onClick={toggleWorkflowProvider}
>
{useProvider ? "Disable Provider" : "Enable Provider"}
{workflowEnabled ? "Disable Provider" : "Enable Provider"}
</Button>
<Button
variant={"success"}
disabled={useProvider === false}
disabled={workflowEnabled === false}
title={`Refresh the app list from the remote workflow`}
onClick={fetchWorkflowData}
>
Expand All @@ -105,12 +120,12 @@ function WorkflowTab() {
<Card.Header>
<div className="d-flex gap-2">
<i className="bi bi-cloud"></i>
Workflow Data
Remote App List
</div>
</Card.Header>
<Card.Body>
{workflow.isLoading ? (
<h1>Loading...</h1>
<h2>Loading...</h2>
) : (
<>
{workflow.data.length > 0 ? (
Expand All @@ -127,7 +142,7 @@ function WorkflowTab() {
<div className="d-flex justify-content-between">
<small className="text-muted">Last update: 3 mins ago</small>
<div>
{!useProvider ? (
{!workflowEnabled ? (
<small className="text-muted">❌ Disabled</small>
) : workflow.isLoading ? (
<small className="text-muted">🚀 Fetching...</small>
Expand Down
7 changes: 5 additions & 2 deletions src/pages/Options/components/AddButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ type Props = {
};

function AddButton({ onClick }: Props) {
const handler = onClick ?? function () {};
return (
<Button className="btn-sm mx-5" variant="primary" onClick={handler}>
<Button
className="btn-sm mx-5"
variant="primary"
onClick={(e) => onClick && onClick(e)}
>
Add +
</Button>
);
Expand Down
8 changes: 1 addition & 7 deletions src/pages/Options/components/AppForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import clsx from "clsx";
import React from "react";
import React, { useRef } from "react";
import { Button, Col, Form, InputGroup, Row } from "react-bootstrap";
import { Controller, useFieldArray, useForm } from "react-hook-form";

Expand Down Expand Up @@ -41,8 +41,6 @@ function AppForm({ app, onSave, onCancel }: Props) {
defaultValues: { ...app },
});

// console.log(watch());

const hashFields = useFieldArray({ name: "hash", control });
const queryFields = useFieldArray({ name: "query", control });

Expand Down Expand Up @@ -217,10 +215,6 @@ function AppForm({ app, onSave, onCancel }: Props) {
</Form.Group>
</Col>
</Row>
{/*
<Row>
<RetoolAppUrl domain={domain} app={watch()} />
</Row> */}

<Row>
<RetoolAppUrl2 domain={domain} app={watch()} />
Expand Down
Loading

0 comments on commit 808cd79

Please sign in to comment.