UI improvements (#240)

some UI improvements:
- fixed password toggle button
- extend conversion to kebab case
- fixed outside click on the alert dropdown
- update logspace ui reference
This commit is contained in:
anovazzi1 2023-05-02 22:56:48 -03:00 • committed by GitHub
commit db951cde20
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 136 additions and 123 deletions

View file

@ -24,7 +24,7 @@ export default function App() {
setShowSideBar(true); setShowSideBar(true);
setIsStackedOpen(true); setIsStackedOpen(true);
}, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]); }, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]);
const {hardReset} = useContext(TabsContext) const { hardReset } = useContext(TabsContext);
const { const {
errorData, errorData,
errorOpen, errorOpen,
@ -108,7 +108,7 @@ export default function App() {
onReset={() => { onReset={() => {
window.localStorage.removeItem("tabsData"); window.localStorage.removeItem("tabsData");
window.localStorage.clear(); window.localStorage.clear();
hardReset() hardReset();
window.location.href = window.location.href; window.location.href = window.location.href;
}} }}
FallbackComponent={CrashErrorComponent} FallbackComponent={CrashErrorComponent}
@ -158,7 +158,7 @@ export default function App() {
<a <a
target={"_blank"} target={"_blank"}
href="https://logspace.ai/" href="https://logspace.ai/"
className="absolute bottom-1 left-1 text-gray-500 text-xs cursor-pointer font-sans tracking-wide" className="absolute bottom-2 left-6 text-gray-300 px-2 rounded-lg text-xs cursor-pointer font-sans tracking-wide bg-gray-800 dark:bg-gray-300 dark:text-gray-800 "
> >
Created by Logspace Created by Logspace
</a> </a>

View file

@ -3,7 +3,7 @@ import {
classNames, classNames,
nodeColors, nodeColors,
nodeIcons, nodeIcons,
snakeToNormalCase, toNormalCase,
} from "../../utils"; } from "../../utils";
import ParameterComponent from "./components/parameterComponent"; import ParameterComponent from "./components/parameterComponent";
import { typesContext } from "../../contexts/typesContext"; import { typesContext } from "../../contexts/typesContext";
@ -192,8 +192,8 @@ export default function GenericNode({
data.node.template[t].display_name data.node.template[t].display_name
? data.node.template[t].display_name ? data.node.template[t].display_name
: data.node.template[t].name : data.node.template[t].name
? snakeToNormalCase(data.node.template[t].name) ? toNormalCase(data.node.template[t].name)
: snakeToNormalCase(t) : toNormalCase(t)
} }
name={t} name={t}
tooltipTitle={ tooltipTitle={

View file

@ -27,9 +27,9 @@ export default function InputComponent({
<input <input
value={myValue} value={myValue}
className={classNames( className={classNames(
"block w-full form-input dark:bg-gray-900 dark:border-gray-600 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm", "block w-full pr-12 form-input dark:bg-gray-900 dark:border-gray-600 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm",
disabled ? " bg-gray-200 dark:bg-gray-700" : "", disabled ? " bg-gray-200 dark:bg-gray-700" : "",
password && !pwdVisible ? "password" : "" password && !pwdVisible && myValue!=="" ? "password" : ""
)} )}
placeholder="Type a text" placeholder="Type a text"
onChange={(e) => { onChange={(e) => {

View file

@ -3,7 +3,7 @@ import { XMarkIcon } from "@heroicons/react/24/outline";
import { Fragment, useContext, useRef, useState } from "react"; import { Fragment, useContext, useRef, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext"; import { PopUpContext } from "../../contexts/popUpContext";
import { NodeDataType } from "../../types/flow"; import { NodeDataType } from "../../types/flow";
import { nodeColors, nodeIcons, snakeToNormalCase } from "../../utils"; import { nodeColors, nodeIcons, toNormalCase } from "../../utils";
import { typesContext } from "../../contexts/typesContext"; import { typesContext } from "../../contexts/typesContext";
import ModalField from "./components/ModalField"; import ModalField from "./components/ModalField";
@ -99,10 +99,10 @@ export default function NodeModal({ data }: { data: NodeDataType }) {
data.node.template[t].display_name data.node.template[t].display_name
? data.node.template[t].display_name ? data.node.template[t].display_name
: data.node.template[t].name : data.node.template[t].name
? snakeToNormalCase( ? toNormalCase(
data.node.template[t].name data.node.template[t].name
) )
: snakeToNormalCase(t) : toNormalCase(t)
} }
required={data.node.template[t].required} required={data.node.template[t].required}
id={ id={

View file

@ -9,7 +9,7 @@ import { PopUpContext } from "../../contexts/popUpContext";
import { FlowType, NodeType } from "../../types/flow"; import { FlowType, NodeType } from "../../types/flow";
import { TabsContext } from "../../contexts/tabsContext"; import { TabsContext } from "../../contexts/tabsContext";
import { alertContext } from "../../contexts/alertContext"; import { alertContext } from "../../contexts/alertContext";
import { classNames, snakeToNormalCase } from "../../utils"; import { toNormalCase } from "../../utils";
import { typesContext } from "../../contexts/typesContext"; import { typesContext } from "../../contexts/typesContext";
import ChatMessage from "./chatMessage"; import ChatMessage from "./chatMessage";
import { FaEraser } from "react-icons/fa"; import { FaEraser } from "react-icons/fa";
@ -230,7 +230,7 @@ export default function ChatModal({
`${type} is missing ${ `${type} is missing ${
template.display_name template.display_name
? template.display_name ? template.display_name
: snakeToNormalCase(template[t].name) : toNormalCase(template[t].name)
}.`, }.`,
] ]
: [] : []

View file

@ -16,7 +16,7 @@ import { error } from "console";
import { alertContext } from "../../contexts/alertContext"; import { alertContext } from "../../contexts/alertContext";
import LoadingComponent from "../../components/loadingComponent"; import LoadingComponent from "../../components/loadingComponent";
import { FlowType } from "../../types/flow"; import { FlowType } from "../../types/flow";
import { classNames } from "../../utils"; import { classNames, toNormalCase } from "../../utils";
export default function ImportModal() { export default function ImportModal() {
const [open, setOpen] = useState(true); const [open, setOpen] = useState(true);
@ -215,7 +215,7 @@ export default function ImportModal() {
setModalOpen(false); setModalOpen(false);
}} }}
textColor="text-emerald-400" textColor="text-emerald-400"
title={example.name} title={toNormalCase(example.name)}
></ButtonBox> ></ButtonBox>
</div> </div>
); );

View file

@ -5,11 +5,11 @@ import { TabsContext } from "../../../../contexts/tabsContext";
import FlowPage from "../.."; import FlowPage from "../..";
import { darkContext } from "../../../../contexts/darkContext"; import { darkContext } from "../../../../contexts/darkContext";
import { import {
ArrowDownTrayIcon, ArrowDownTrayIcon,
ArrowUpTrayIcon, ArrowUpTrayIcon,
BellIcon, BellIcon,
MoonIcon, MoonIcon,
SunIcon, SunIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
import { PopUpContext } from "../../../../contexts/popUpContext"; import { PopUpContext } from "../../../../contexts/popUpContext";
import AlertDropdown from "../../../../alerts/alertDropDown"; import AlertDropdown from "../../../../alerts/alertDropDown";
@ -22,96 +22,101 @@ export default function TabsManagerComponent() {
const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } = const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } =
useContext(TabsContext); useContext(TabsContext);
const { openPopUp } = useContext(PopUpContext); const { openPopUp } = useContext(PopUpContext);
const {templates} = useContext(typesContext) const { templates } = useContext(typesContext);
const AlertWidth = 256; const AlertWidth = 256;
const { dark, setDark } = useContext(darkContext); const { dark, setDark } = useContext(darkContext);
const { notificationCenter, setNotificationCenter } = const { notificationCenter, setNotificationCenter } =
useContext(alertContext); useContext(alertContext);
useEffect(() => { useEffect(() => {
//create the first flow //create the first flow
if (flows.length === 0&& Object.keys(templates).length>0) { if (flows.length === 0 && Object.keys(templates).length > 0) {
addFlow(); addFlow();
} }
}, [addFlow, flows.length,templates]); }, [addFlow, flows.length, templates]);
return ( return (
<div className="h-full w-full flex flex-col"> <div className="h-full w-full flex flex-col">
<div className="w-full flex pr-2 flex-row text-center items-center bg-gray-100 dark:bg-gray-800 px-2"> <div className="w-full flex pr-2 flex-row text-center items-center bg-gray-100 dark:bg-gray-800 px-2">
{flows.map((flow, index) => { {flows.map((flow, index) => {
return ( return (
<TabComponent <TabComponent
onClick={() => setTabIndex(index)} onClick={() => setTabIndex(index)}
selected={index === tabIndex} selected={index === tabIndex}
key={index} key={index}
flow={flow} flow={flow}
/> />
); );
})} })}
<TabComponent <TabComponent
onClick={() => { onClick={() => {
addFlow(); addFlow();
}} }}
selected={false} selected={false}
flow={null} flow={null}
/> />
<div className="ml-auto mr-2 flex gap-3"> <div className="ml-auto mr-2 flex gap-3">
<button <button
onClick={() => openPopUp(<ImportModal />)} onClick={() => openPopUp(<ImportModal />)}
className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-600 hover:text-gray-500" className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-600 hover:text-gray-500"
> >
Import <ArrowUpTrayIcon className="w-5 h-5" /> Import <ArrowUpTrayIcon className="w-5 h-5" />
</button> </button>
<button <button
onClick={() => openPopUp(<ExportModal />)} onClick={() => openPopUp(<ExportModal />)}
className="flex items-center gap-1 mr-2 text-sm text-gray-600 hover:text-gray-500" className="flex items-center gap-1 mr-2 text-sm text-gray-600 hover:text-gray-500"
> >
Export <ArrowDownTrayIcon className="h-5 w-5" /> Export <ArrowDownTrayIcon className="h-5 w-5" />
</button> </button>
<button <button
className="text-gray-600 hover:text-gray-500 " className="text-gray-600 hover:text-gray-500 "
onClick={() => { onClick={() => {
setDark(!dark); setDark(!dark);
}} }}
> >
{dark ? ( {dark ? (
<SunIcon className="h-5 w-5" /> <SunIcon className="h-5 w-5" />
) : ( ) : (
<MoonIcon className="h-5 w-5" /> <MoonIcon className="h-5 w-5" />
)} )}
</button> </button>
<button <button
className="text-gray-600 hover:text-gray-500 relative" className="text-gray-600 hover:text-gray-500 relative"
onClick={(event: React.MouseEvent<HTMLElement>) => { onClick={(event: React.MouseEvent<HTMLElement>) => {
setNotificationCenter(false); setNotificationCenter(false);
const top = (event.target as Element).getBoundingClientRect().top; const top = (event.target as Element).getBoundingClientRect().top;
const left = (event.target as Element).getBoundingClientRect() const left = (event.target as Element).getBoundingClientRect()
.left; .left;
openPopUp( openPopUp(
<div <>
className="z-10 absolute" <div
style={{ top: top + 20, left: left - AlertWidth }} className="z-10 absolute"
> style={{ top: top + 20, left: left - AlertWidth }}
<AlertDropdown /> >
</div> <AlertDropdown />
); </div>
}} <div className="h-screen w-screen fixed top-0 left-0">
>
{notificationCenter && ( </div>
<div className="absolute w-1.5 h-1.5 rounded-full bg-red-600 right-[3px]"></div> </>
)} );
<BellIcon className="h-5 w-5" aria-hidden="true" /> }}
</button> >
</div> {notificationCenter && (
</div> <div className="absolute w-1.5 h-1.5 rounded-full bg-red-600 right-[3px]"></div>
<div className="w-full h-full"> )}
<ReactFlowProvider> <BellIcon className="h-5 w-5" aria-hidden="true" />
{flows[tabIndex] ? ( </button>
<FlowPage flow={flows[tabIndex]}></FlowPage> </div>
) : ( </div>
<></> <div className="w-full h-full">
)} <ReactFlowProvider>
</ReactFlowProvider> {flows[tabIndex] ? (
</div> <FlowPage flow={flows[tabIndex]}></FlowPage>
</div> ) : (
); <></>
)}
</ReactFlowProvider>
</div>
</div>
);
} }

View file

@ -316,16 +316,25 @@ export function toFirstUpperCase(str: string) {
.join(""); .join("");
} }
export function snakeToNormalCase(str: string) { export function toNormalCase(str: string) {
return str let result = str
.split("_") .split("_")
.map((word, index) => { .map((word, index) => {
if (index === 0) { if (index === 0) {
return word[0].toUpperCase() + word.slice(1).toLowerCase(); return word[0].toUpperCase() + word.slice(1).toLowerCase();
} }
return word.toLowerCase(); return word.toLowerCase();
}) })
.join(" "); .join(" ");
return result.split("-")
.map((word, index) => {
if (index === 0) {
return word[0].toUpperCase() + word.slice(1).toLowerCase();
}
return word.toLowerCase();
})
.join(" ");
} }
export function normalCaseToSnakeCase(str: string) { export function normalCaseToSnakeCase(str: string) {
@ -388,16 +397,15 @@ export function isValidConnection(
} }
export function removeApiKeys(flow: FlowType): FlowType { export function removeApiKeys(flow: FlowType): FlowType {
let cleanFLow = _.cloneDeep(flow); let cleanFLow = _.cloneDeep(flow);
cleanFLow.data.nodes.forEach((node) => { cleanFLow.data.nodes.forEach((node) => {
for (const key in node.data.node.template) { for (const key in node.data.node.template) {
if (key.includes("api")) { if (key.includes("api")) {
console.log(node.data.node.template[key]); node.data.node.template[key].value = "";
node.data.node.template[key].value = ""; }
} }
} });
}); return cleanFLow;
return cleanFLow;
} }
export function updateObject<T extends Record<string, any>>( export function updateObject<T extends Record<string, any>>(