Skip to content

Commit

Permalink
more styling and refactoring components
Browse files Browse the repository at this point in the history
khill-fbmc committed Oct 16, 2024
1 parent cadc8ac commit 5ad716b
Showing 8 changed files with 226 additions and 90 deletions.
4 changes: 2 additions & 2 deletions src/hooks/useEditMode.ts
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ export function useEditMode() {
const isEditing = useStore((s) => s.isEditing);
const setEditMode = useStore((s) => s.setEditMode);
const startEditMode = () => setEditMode(true);
const endEditMode = () => setEditMode(false);
const stopEditMode = () => setEditMode(false);

return { isEditing, setEditMode, startEditMode, endEditMode };
return { isEditing, setEditMode, startEditMode, stopEditMode };
}
3 changes: 3 additions & 0 deletions src/hooks/useRetoolAppUrl.ts
Original file line number Diff line number Diff line change
@@ -17,6 +17,9 @@ function composeAppUrl(domain: string, app: RetoolApp) {

app.query.forEach((q) => url.searchParams.append(q.param, q.value));

url.searchParams.append("_version", app.version);
url.searchParams.append("_environment", app.env);

if (app.hash.length === 0) {
return `${url.toString()}`;
}
44 changes: 36 additions & 8 deletions src/pages/Options/Tabs/ConfigTab.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
import React from "react";
import { Col, Container, Row } from "react-bootstrap";
import React, { useMemo, useState } from "react";
import { Button, Col, Container, Row } from "react-bootstrap";
import { FormProvider, 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";

const NEW_APP: RetoolApp = {
name: "",
public: false,
version: "latest",
env: "development",
hash: [],
query: [],
};

function ConfigTab() {
const methods = useForm<RetoolApp>();
const { isEditing, startEditMode } = useEditMode();

const app = useStore((s) => s.getActiveApp());
const updateActiveApp = useStore((s) => s.updateActiveApp);

const [creatingNew, setCreatingNew] = useState(false);
const createNewApp = () => {
setCreatingNew(true);
};

return (
<>
@@ -25,7 +40,17 @@ function ConfigTab() {
<DomainInput />

<h3 className="mt-2">Current App</h3>
{!isEditing ? (
{isEditing ? (
<FormProvider {...methods}>
<AppForm
app={app!}
onSave={(data) => {
updateActiveApp(data);
successToast("Edits saved.");
}}
/>
</FormProvider>
) : (
<Container className="pt-2">
<AppCard
isActive
@@ -34,13 +59,16 @@ function ConfigTab() {
onEdit={() => startEditMode()}
/>
</Container>
) : (
<FormProvider {...methods}>
<AppForm app={app!} />
</FormProvider>
)}
</Col>
</Row>
{!isEditing && !creatingNew && (
<div className="d-flex mt-5">
<Button variant="success" className="mx-auto">
Create New
</Button>
</div>
)}
</>
);
}
91 changes: 49 additions & 42 deletions src/pages/Options/components/AppCard.tsx
Original file line number Diff line number Diff line change
@@ -29,12 +29,23 @@ type EditProps = BaseProps & {
type Props = EditProps | StdProps;

function AppCard({ app, isActive, ...props }: Props) {
const { endEditMode } = useEditMode();
const domain = useStore((s) => s.domain);
const setActiveApp = useStore((s) => s.setActiveApp);

const { stopEditMode } = useEditMode();
const appUrl = useRetoolAppUrl(domain, app);

const onPreview = () => window.open(appUrl, "_blank");

const onActivate = () => {
if (props.editable) {
props.onEdit();
} else {
stopEditMode();
setActiveApp(app?.name);
}
};

return (
<Card
className={clsx("app-card", isActive && "active")}
@@ -53,59 +64,55 @@ function AppCard({ app, isActive, ...props }: Props) {
</Card.Header>
<Card.Body>
<Row>
{app?.query && (
<Col>
<h5>Query Params</h5>
<Col>
<h5>Query Params</h5>
{app?.query && app.query.length ? (
<Parameters type="query" params={app.query} />
</Col>
)}
{app?.hash && (
<Col>
<h5>Hash Params</h5>
) : (
<small className="text-muted">none</small>
)}
</Col>

<Col>
<h5>Hash Params</h5>
{app?.hash && app.hash.length ? (
<Parameters type="hash" params={app.hash} />
</Col>
)}
) : (
<small className="text-muted">none</small>
)}
</Col>
</Row>
<div className="d-flex my-2 justify-content-center">
<a
target="_blank"
rel="noreferrer"
className="btn-sm d-flex align-items-center gap-1"
href={appUrl}
>
<i className="bi bi-box-arrow-up-right"></i>Open in Retool
</a>
</div>
</Card.Body>
<Card.Footer>
<div className="d-flex justify-space-between">
<div className="d-flex justify-content-between">
<div className="d-flex gap-2 align-items-center">
<AppVisibilityBadge isPublic={app?.public} />
<Badge pill bg="secondary">
{app?.version[0] === "l" ? app?.version : `v${app?.version}`}
</Badge>
</div>

<Button
className="btn-sm ms-auto"
onClick={() => {
if (props.editable) {
props.onEdit();
} else {
endEditMode();
setActiveApp(app?.name);
<div className="d-flex gap-2 align-items-end">
<Button
variant="outline-success"
className="btn-sm d-flex gap-2"
onClick={onPreview}
>
<i className="bi bi-box-arrow-up-right"></i>Preview
</Button>
<Button
className="btn-sm mx-auto"
onClick={onActivate}
variant={
props.editable
? "outline-primary"
: isActive
? "primary"
: "outline-primary"
}
}}
variant={
props.editable
? "outline-success"
: isActive
? "primary"
: "outline-primary"
}
>
{props.editable ? "Edit" : isActive ? "⭐️ Active" : "Activate"}
</Button>
>
{props.editable ? "Edit" : isActive ? "⭐️ Active" : "Activate"}
</Button>
</div>
</div>
</Card.Footer>
</Card>
52 changes: 29 additions & 23 deletions src/pages/Options/components/AppForm.tsx
Original file line number Diff line number Diff line change
@@ -18,13 +18,14 @@ import type { RetoolApp } from "@/types/extension";

type Props = {
app: RetoolApp;
onSave?: SubmitHandler<RetoolApp>;
};

const INIT_PARAM = { param: "", value: "" };

function AppForm({ app }: Props) {
function AppForm({ app, onSave }: Props) {
const { domain } = useDomain();
const { setEditMode } = useEditMode();
const { stopEditMode } = useEditMode();
const updateActiveApp = useStore((s) => s.updateActiveApp);

const {
@@ -53,8 +54,19 @@ function AppForm({ app }: Props) {
errorToast(message);
};

const onCancel = () => {
resetForm();
stopEditMode();
};

const onDelete = () => {
resetForm();
stopEditMode();
alert("BALEETED!");
};

return (
<Form onSubmit={handleSubmit(onSubmit, onError)}>
<Form onSubmit={handleSubmit(onSave ?? onSubmit, onError)}>
<Form.Group className="mb-4" controlId="app">
<div className="d-flex justify-content-between">
<Form.Label>
@@ -172,12 +184,7 @@ function AppForm({ app }: Props) {
<Form.Control placeholder="value" {...field} />
)}
/>
<TrashButton
onClick={() => {
console.log("Removing Query IDX", index);
queryFields.remove(index);
}}
/>
<TrashButton onClick={() => queryFields.remove(index)} />
</InputGroup>
))}
<AddButton onClick={() => queryFields.append(INIT_PARAM)} />
@@ -208,41 +215,40 @@ function AppForm({ app }: Props) {
<Form.Control placeholder="value" {...field} />
)}
/>
<TrashButton
onClick={() => {
console.log("Removing Hash IDX", index);
hashFields.remove(index);
}}
/>
<TrashButton onClick={() => hashFields.remove(index)} />
</InputGroup>
))}
<AddButton onClick={() => hashFields.append(INIT_PARAM)} />
</Form.Group>
</Col>
</Row>

{/*
<Row>
<RetoolAppUrl domain={domain} app={watch()} />
</Row>
</Row> */}

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

<div className="d-flex gap-5">
<Button
className="px-3"
className="d-flex gap-2 px-3"
variant="outline-danger"
onClick={() => {
resetForm();
setEditMode(false);
}}
onClick={onCancel}
>
Cancel
<i className="bi bi-x-octagon"></i>Cancel
</Button>
<Button className="flex-fill px-5" type="submit" variant="success">
Save
</Button>
<Button
className="d-flex gap-2 px-3"
variant="outline-danger"
onClick={onDelete}
>
<i className="bi bi-trash"></i>Delete
</Button>
</div>
</Form>
);
43 changes: 43 additions & 0 deletions src/pages/Options/components/ParameterList.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.parameter-list {
list-style: none;
margin-left: 0;
padding-left: 0;

li {
padding-left: 1.5em;
text-indent: -1em;
}

li::before {
color: grey;
padding-right: 5px;
}

li:not(:first-child)::before {
content: "&";
}

li.query-param:first-child::before {
content: "?";
}

li.hash-param:first-child::before {
content: "#";
}

.param-name {
margin-right: 5px;
}

.param-name::after {
content: "=";
color: grey;
padding-left: 5px;
}

.param-value {
font-weight: bold;
}


}
23 changes: 23 additions & 0 deletions src/pages/Options/components/ParameterList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import "./ParameterList.css";

import React from "react";

type Props = {
type: "query" | "hash";
params: [param: string, value: string][];
};

function ParameterList({ params, type }: Props) {
return (
<ul className="parameter-list">
{params.map(([param, value]) => (
<li key={param} className={`${type}-param`}>
<span className="param-name">{param}</span>
<span className="param-value">{value}</span>
</li>
))}
</ul>
);
}

export default ParameterList;
56 changes: 41 additions & 15 deletions src/pages/Options/components/RetoolAppUrl2.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,53 @@
import JsonView from "@uiw/react-json-view";
import { githubLightTheme } from "@uiw/react-json-view/githubLight";
import React, { useMemo } from "react";
import { Button, Form, InputGroup } from "react-bootstrap";
import React from "react";
import { Col, Row } from "react-bootstrap";

import { useRetoolAppUrl } from "@/hooks/useRetoolAppUrl";

import ParameterList from "./ParameterList";

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

type ParameterListParams = React.ComponentProps<typeof ParameterList>["params"];

function RetoolAppUrl2({ app, domain }: { app: RetoolApp; domain: string }) {
const url = useRetoolAppUrl(domain, app);
const jsonUrl = useMemo(() => new URL(url), [url]);
const fullUrl = useRetoolAppUrl(domain, app);
const url = new URL(fullUrl);

const queryParams = Array.from(url.searchParams.entries());

const hashParams: ParameterListParams = app.hash.map((p) => {
return [p.param, p.value];
});

console.log(hashParams);

return (
<div className="mb-4">
<h3>Composed URL 2</h3>
<JsonView
value={jsonUrl}
collapsed={3}
displayDataTypes={false}
enableClipboard={false}
style={githubLightTheme}
shortenTextAfterLength={0}
/>
<h4>Composed URL</h4>
<a
href={fullUrl}
target="_blank"
rel="noreferrer"
title={`Open App in Retool (${app.name})`}
>
<p className="lead">{url.origin + url.pathname}</p>
</a>
<Row>
<Col>
<h5>Query Params:</h5>
<ul className="parameter-list">
<ParameterList type="query" params={queryParams} />
</ul>
</Col>
<Col>
<h5>Hash Params:</h5>
<ul className="parameter-list">
{hashParams.length > 0 && (
<ParameterList type="hash" params={hashParams} />
)}
</ul>
</Col>
</Row>
</div>
);
}

0 comments on commit 5ad716b

Please sign in to comment.