From 2fcb43aee26be240786a0941fa821b6cb0b82cc1 Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Thu, 4 Jul 2024 18:03:35 +0200 Subject: [PATCH 1/9] feat: datasources cancel button --- .../main/views/DataSources/DataSources.tsx | 3 +- .../DataSources/components/AuthFields.tsx | 1 + .../components/DataSourceHeaders.tsx | 41 +++++++++---- .../DataSources/components/SectionHeader.tsx | 13 +++- packages/main/views/DataSources/ui/Field.tsx | 5 +- .../main/views/DataSources/views/Settings.tsx | 59 ++++++++++++++----- 6 files changed, 89 insertions(+), 33 deletions(-) diff --git a/packages/main/views/DataSources/DataSources.tsx b/packages/main/views/DataSources/DataSources.tsx index 2b124df4..a898fb7b 100644 --- a/packages/main/views/DataSources/DataSources.tsx +++ b/packages/main/views/DataSources/DataSources.tsx @@ -42,8 +42,7 @@ export default function DataSources() {
- - +
{ - const dispatch: any = useDispatch(); - - const dataSources = useSelector((store: any) => store.dataSources); +type HeaderEntry = { + id: string + header: string + value: string +} +type DataSourceHadersProps = { + id: string; + cors?: boolean + headers: HeaderEntry[] + dataSources: any + onDsChange: (prev:any) => void +} + +export const DataSourceHeaders = (props: DataSourceHadersProps) => { + + // const dataSources = useSelector((store: any) => store.dataSources); const [editing, setEditing] = useState(false); - const { headers, id } = props; + const { headers, id, onDsChange, dataSources } = props; const [cors, setCors] = useState(props?.cors || false); const onCorsChange = (e: any) => { @@ -27,9 +38,11 @@ export const DataSourceHeaders = (props: any) => { } return ds; }); + setCors(() => value); - localStorage.setItem("dataSources", JSON.stringify(newDataSources)); - dispatch(setDataSources(newDataSources)); + onDsChange(()=>newDataSources) + // localStorage.setItem("dataSources", JSON.stringify(newDataSources)); + // dispatch(setDataSources(newDataSources)); }; const onChange = (e: any, headerId: any, name: any) => { @@ -53,8 +66,10 @@ export const DataSourceHeaders = (props: any) => { return ds; }); - localStorage.setItem("dataSources", JSON.stringify(newDataSources)); - dispatch(setDataSources(newDataSources)); + // localStorage.setItem("dataSources", JSON.stringify(newDataSources)); + // dispatch(setDataSources(newDataSources)); + + onDsChange(()=>newDataSources) setTimeout(() => { setEditing(() => false); }, 800); @@ -84,9 +99,9 @@ export const DataSourceHeaders = (props: any) => { } return ds; }); - - localStorage.setItem("dataSources", JSON.stringify(newDataSources)); - dispatch(setDataSources(newDataSources)); + onDsChange(()=> newDataSources) + // localStorage.setItem("dataSources", JSON.stringify(newDataSources)); + // dispatch(setDataSources(newDataSources)); } }; diff --git a/packages/main/views/DataSources/components/SectionHeader.tsx b/packages/main/views/DataSources/components/SectionHeader.tsx index a64b5ae0..c704b93e 100644 --- a/packages/main/views/DataSources/components/SectionHeader.tsx +++ b/packages/main/views/DataSources/components/SectionHeader.tsx @@ -80,9 +80,18 @@ const InputErrorWarning = ({ errorText }: { errorText: string }) => { ); }; -export function SectionHeader(props: any) { +export type SectionHeaderProps = { + isEditing?: boolean + isEdit: boolean + isAdd:boolean + title: string + fieldErrors: any + onClickAdd?: () => void +} + +export function SectionHeader(props: SectionHeaderProps) { const { onClickAdd, isAdd, title, isEditing, fieldErrors } = props; - const dispatch: any = useDispatch(); + const dispatch: any = useDispatch(); const [isSaved, setIsSaved] = useState(false); useEffect(() => { diff --git a/packages/main/views/DataSources/ui/Field.tsx b/packages/main/views/DataSources/ui/Field.tsx index 3b5d492b..38194298 100644 --- a/packages/main/views/DataSources/ui/Field.tsx +++ b/packages/main/views/DataSources/ui/Field.tsx @@ -2,7 +2,10 @@ import { InputGroup, Label, Input } from "../styles"; import DOMPurify from "isomorphic-dompurify"; export const Field = (props: any) => { const { value, label, onChange, locked, type, placeholder, error, labelWidth} = props; - return ( + + // set an initial value and a value for cancelling + // that should be previous stored value + return ( { - const { headers, id, linkedFields, name, url, cors }: any = props; + const state = useSelector(({ dataSources }: any) => dataSources); + // sets the initial and editable data + const [settingsData, setSettingsData] = useState(props) + const [initialDs, setInitialDs] = useState(state) + // we will pass all props into the processor and from there get the initial values - const dispatch: any = useDispatch(); + //console.log(props) // this will be the initial fields before saving + // the ones triggered on the cancel button + - const state = useSelector(({ dataSources }: any) => dataSources); + // const { headers, id, linkedFields, name, url, cors }: any = props; + + + // const dispatch: any = useDispatch(); const [fieldErrors, setFieldErrors] = useState({ url: false, protocol: false, }); const onFieldChange = (prop: any, value: any) => { + console.log(prop, value) let val = value; - const arrayClone = JSON.parse(JSON.stringify(state)); + const arrayClone = JSON.parse(JSON.stringify(initialDs)); arrayClone.forEach((field: any) => { - if (field.id === id) { + if (field.id === settingsData.id) { field[prop] = val; } }); @@ -38,6 +49,7 @@ export const Settings = (props: any) => { const [isEditing, setIsEditing] = useState(false); const checkURLProtocol = (value: URL | any) => { + try { const current_protocol = window.location.protocol; const value_protocol = new URL(value)["protocol"]; @@ -50,6 +62,7 @@ export const Settings = (props: any) => { const onChange = (e: any, name: any) => { setIsEditing(() => true); const value = e.target.value; + console.log(value,name) // check here if name === url if (name === "url") { const protocol_match = checkURLProtocol(value); @@ -69,8 +82,11 @@ export const Settings = (props: any) => { url: false, })); const newVal = onFieldChange(name, value); - localStorage.setItem("dataSources", JSON.stringify(newVal)); - dispatch(setDataSources(newVal)); + setInitialDs( newVal) + //setSettingsData( (prev) => ({...prev, ...newVal})) + + // localStorage.setItem("dataSources", JSON.stringify(newVal)); + // dispatch(setDataSources(newVal)); setTimeout(() => { setIsEditing(() => false); }, 800); @@ -78,13 +94,20 @@ export const Settings = (props: any) => { } const newVal = onFieldChange(name, value); - localStorage.setItem("dataSources", JSON.stringify(newVal)); - dispatch(setDataSources(newVal)); + setInitialDs(newVal) + //setSettingsData( () => newVal) + // localStorage.setItem("dataSources", JSON.stringify(newVal)); + // dispatch(setDataSources(newVal)); setTimeout(() => { setIsEditing(() => false); }, 800); }; + useEffect(()=>{ + setSettingsData((prev) => ({ ...prev, ...initialDs?.find(f => f.id === prev.id)})) + + },[initialDs]) + return ( { onChange(e, "name")} /> onChange(e, "url")} @@ -114,9 +137,15 @@ export const Settings = (props: any) => { - + - + ); }; From aaed261509cbaf07db00c5b9755411b47549ed23 Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Thu, 4 Jul 2024 18:13:20 +0200 Subject: [PATCH 2/9] fix: auth fields --- .../DataSources/components/AuthFields.tsx | 29 ++++++++++++------- .../DataSources/components/SectionHeader.tsx | 8 ++--- .../main/views/DataSources/views/Settings.tsx | 13 +++++++-- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/packages/main/views/DataSources/components/AuthFields.tsx b/packages/main/views/DataSources/components/AuthFields.tsx index 50459467..ef44dfd0 100644 --- a/packages/main/views/DataSources/components/AuthFields.tsx +++ b/packages/main/views/DataSources/components/AuthFields.tsx @@ -1,18 +1,24 @@ import { useEffect, useMemo, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import setDataSources from "../store/setDataSources"; import { InputCol, InputCont } from "../styles"; import { QrynSwitch, Select, Field } from "../ui"; import { TextAreaField } from "../ui/TextArea"; import { SectionHeader } from "./SectionHeader"; import DOMPurify from "isomorphic-dompurify"; -export function AuthFields(props: any) { +export type AuthFieldsProps = { + auth?: any + id?: string + dataSources?: any + onDsChange?: (prev:any) => void + fieldErrors?: any +} + +export function AuthFields(props: AuthFieldsProps) { // console.log(props) - const { auth, id } = props; - const dispatch: any = useDispatch(); + const { auth, id, dataSources, onDsChange } = props; + //const dispatch: any = useDispatch(); - const dataSources = useSelector((store: any) => store.dataSources); + //const dataSources = useSelector((store: any) => store.dataSources); const [activeFields, setActiveFields] = useState([]); const [isEditing, setIsEditing] = useState(false); @@ -46,9 +52,10 @@ export function AuthFields(props: any) { return dataSource; }); - localStorage.setItem("dataSources", JSON.stringify(newDataSources)); + onDsChange(()=> newDataSources) + //localStorage.setItem("dataSources", JSON.stringify(newDataSources)); - dispatch(setDataSources(newDataSources)); + //dispatch(setDataSources(newDataSources)); return newDataSources; }; @@ -108,9 +115,9 @@ export function AuthFields(props: any) { return ds; }); - localStorage.setItem("dataSources", JSON.stringify(newDataSources)); - dispatch(setDataSources(newDataSources)); - + //localStorage.setItem("dataSources", JSON.stringify(newDataSources)); + //dispatch(setDataSources(newDataSources)); + onDsChange(()=> newDataSources) setTimeout(() => { setIsEditing(() => false); }, 600); diff --git a/packages/main/views/DataSources/components/SectionHeader.tsx b/packages/main/views/DataSources/components/SectionHeader.tsx index c704b93e..94fe6426 100644 --- a/packages/main/views/DataSources/components/SectionHeader.tsx +++ b/packages/main/views/DataSources/components/SectionHeader.tsx @@ -82,10 +82,10 @@ const InputErrorWarning = ({ errorText }: { errorText: string }) => { export type SectionHeaderProps = { isEditing?: boolean - isEdit: boolean - isAdd:boolean - title: string - fieldErrors: any + isEdit?: boolean + isAdd?:boolean + title?: string + fieldErrors?: any onClickAdd?: () => void } diff --git a/packages/main/views/DataSources/views/Settings.tsx b/packages/main/views/DataSources/views/Settings.tsx index 032794a3..cf446be1 100644 --- a/packages/main/views/DataSources/views/Settings.tsx +++ b/packages/main/views/DataSources/views/Settings.tsx @@ -135,7 +135,14 @@ export const Settings = (props: any) => { - + { onDsChange={setInitialDs} /> - + ); }; From d03e45f04cf61d5811b5c985a4b99504c159e0ce Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Fri, 5 Jul 2024 19:07:37 +0200 Subject: [PATCH 3/9] fix: linked fields section --- .../DataSources/components/LinkedFields.tsx | 26 +++++++++++++------ .../main/views/DataSources/views/Settings.tsx | 9 +++++-- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/main/views/DataSources/components/LinkedFields.tsx b/packages/main/views/DataSources/components/LinkedFields.tsx index 8a85f880..aed94031 100644 --- a/packages/main/views/DataSources/components/LinkedFields.tsx +++ b/packages/main/views/DataSources/components/LinkedFields.tsx @@ -1,17 +1,25 @@ import { useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; +//import { useDispatch, useSelector } from "react-redux"; import { LinkedFieldItem } from "../classes/LinkedFieldItem"; -import setDataSources from "../store/setDataSources"; +//import setDataSources from "../store/setDataSources"; import { InputCont } from "../styles"; import { LinkedField } from "./LinkedField"; import { SectionHeader } from "./SectionHeader"; -export const LinkedFields = (props: any) => { - const { linkedFields, name, id } = props; +export type LinkedFieldsProps = { + id: string; + name: string; + linkedFields: any; + dataSources: any; + onDsChange: (prev:any) => void +} - const dataSources = useSelector((store: any) => store.dataSources); +export const LinkedFields = (props: LinkedFieldsProps) => { + const { linkedFields, name, id, dataSources, onDsChange } = props; - const dispatch: any = useDispatch(); + //const dataSources = useSelector((store: any) => store.dataSources); + + // const dispatch: any = useDispatch(); const [isEditing, setIsEditing] = useState(false); const onAddLinkedField = () => { @@ -35,8 +43,10 @@ export const LinkedFields = (props: any) => { return m; }); - localStorage.setItem("dataSources", JSON.stringify(newDataSources)); - dispatch(setDataSources(newDataSources)); + onDsChange( () => newDataSources) + + // localStorage.setItem("dataSources", JSON.stringify(newDataSources)); + // dispatch(setDataSources(newDataSources)); }; const fieldEditing = () => { diff --git a/packages/main/views/DataSources/views/Settings.tsx b/packages/main/views/DataSources/views/Settings.tsx index cf446be1..4b2a679a 100644 --- a/packages/main/views/DataSources/views/Settings.tsx +++ b/packages/main/views/DataSources/views/Settings.tsx @@ -153,8 +153,13 @@ export const Settings = (props: any) => { /> + // {...props} + id={settingsData.id} + name={settingsData.name} + onDsChange={setInitialDs} + dataSources={initialDs} + linkedFields={settingsData.linkedFields} /> + ); }; From a2c1d33a3c6d7c12b7f74c72ce3a0d8350219558 Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Mon, 8 Jul 2024 18:24:21 +0200 Subject: [PATCH 4/9] fix: components callbacks --- .../main/views/DataSources/DataSource.tsx | 22 ++- .../DataSources/components/ConfirmSave.tsx | 22 +++ .../components/DataSourceHeaders.tsx | 8 +- .../DataSources/components/FieldErrors.tsx | 30 ++++ .../views/DataSources/components/Header.tsx | 13 +- .../components/InputErrorWarning.tsx | 22 +++ .../DataSources/components/SectionHeader.tsx | 152 ++++++------------ .../DataSources/components/header.styles.ts | 51 ++++++ packages/main/views/DataSources/styles.ts | 108 +++++++------ .../main/views/DataSources/views/Settings.tsx | 17 +- 10 files changed, 278 insertions(+), 167 deletions(-) create mode 100644 packages/main/views/DataSources/components/ConfirmSave.tsx create mode 100644 packages/main/views/DataSources/components/FieldErrors.tsx create mode 100644 packages/main/views/DataSources/components/InputErrorWarning.tsx create mode 100644 packages/main/views/DataSources/components/header.styles.ts diff --git a/packages/main/views/DataSources/DataSource.tsx b/packages/main/views/DataSources/DataSource.tsx index a52c16ad..fadf3bdc 100644 --- a/packages/main/views/DataSources/DataSource.tsx +++ b/packages/main/views/DataSources/DataSource.tsx @@ -1,6 +1,6 @@ import { css, cx } from "@emotion/css"; import { ThemeProvider } from "@emotion/react"; -import { useMemo } from "react"; +import { useCallback, useMemo, useState } from "react"; import { useCookies } from "react-cookie"; import { useDispatch, useSelector } from "react-redux"; import { useParams } from "react-router-dom"; @@ -56,6 +56,8 @@ export function DataSourceSetting(props: any) { "qryn-dev-cookie", "qryn-settings", ]); // for testing cookies feature + + const dispatch: any = useDispatch(); const dataSources = useSelector((store: any) => store.dataSources); const useForAll = () => { @@ -169,7 +171,7 @@ export function DataSourceSetting(props: any) {
- +
); @@ -193,7 +195,11 @@ export const DataSourceSettingHeader = (props: any) => { export function DataSource() { let { id } = useParams(); const theme = useTheme(); + const dispatch:any = useDispatch() + const dataSources = useSelector((store: any) => store.dataSources); + const [dataChanged, setDataChanged] = useState([]) + const datasource = useMemo(() => { if (!dataSources || dataSources.length === 0) { return {}; @@ -202,6 +208,13 @@ export function DataSource() { return dataSources.find((f: any) => f.id === id) || {}; }, [id, dataSources]); + const saveSettings = () => useCallback(()=>{ + dispatch(setDataSources(dataChanged)) + localStorage.setItem("dataSources", JSON.stringify(dataChanged)); + },[dataChanged]) + + + return ( @@ -209,9 +222,12 @@ export function DataSource() {
- +
diff --git a/packages/main/views/DataSources/components/ConfirmSave.tsx b/packages/main/views/DataSources/components/ConfirmSave.tsx new file mode 100644 index 00000000..95d7f2ab --- /dev/null +++ b/packages/main/views/DataSources/components/ConfirmSave.tsx @@ -0,0 +1,22 @@ +import { cx } from '@emotion/css' +import { QrynTheme } from '@ui/theme/types'; +import CheckCircleIcon from "@mui/icons-material/CheckCircle"; +import { confirmSaveLoaderCont, confirmSaveLoaderIcon } from "./header.styles"; + +export type ConfirmSaveProps = { + setIsSaved : (boolean) => void + theme: QrynTheme +} + +export const ConfirmSave = ({ setIsSaved, theme }: ConfirmSaveProps) => { + + return ( +
setIsSaved(false)} + > + {" "} + Saved +
+ ); +}; \ No newline at end of file diff --git a/packages/main/views/DataSources/components/DataSourceHeaders.tsx b/packages/main/views/DataSources/components/DataSourceHeaders.tsx index a01cd8cd..e1aeb45b 100644 --- a/packages/main/views/DataSources/components/DataSourceHeaders.tsx +++ b/packages/main/views/DataSources/components/DataSourceHeaders.tsx @@ -1,7 +1,7 @@ import DeleteOutlineOutlinedIcon from "@mui/icons-material/DeleteOutlineOutlined"; import { nanoid } from "nanoid"; import { useState } from "react"; -import setDataSources from "../store/setDataSources"; +//import setDataSources from "../store/setDataSources"; import { InputCol, InputGroup, Label } from "../styles"; import { Field } from "../ui"; import { SectionHeader } from "./SectionHeader"; @@ -117,8 +117,10 @@ export const DataSourceHeaders = (props: DataSourceHadersProps) => { return ds; }); - localStorage.setItem("dataSources", JSON.stringify(newDataSources)); - dispatch(setDataSources(newDataSources)); + onDsChange(()=> newDataSources) + + // localStorage.setItem("dataSources", JSON.stringify(newDataSources)); + // dispatch(setDataSources(newDataSources)); }; return ( diff --git a/packages/main/views/DataSources/components/FieldErrors.tsx b/packages/main/views/DataSources/components/FieldErrors.tsx new file mode 100644 index 00000000..180847c1 --- /dev/null +++ b/packages/main/views/DataSources/components/FieldErrors.tsx @@ -0,0 +1,30 @@ +import { InputErrorWarning } from "./InputErrorWarning"; + +export const FIELD_ERROR_TEXT = { + protocol: "mixed_content", + url: "complete_url", +}; + +type FieldError = Record; + +export type FieldErrorProps = { + fieldErrors?: FieldError; +}; + +export const mapErrors = (fieldErrors: FieldError) => { + return Object.keys(fieldErrors) + .map((error) => error) + .filter((f) => Boolean(fieldErrors[f])); +}; + +export const FieldErrors = (props: FieldErrorProps) => { + const { fieldErrors } = props; + if (!fieldErrors) return <>; + return ( + <> + {mapErrors(fieldErrors)?.map((error, key) => ( + + ))} + + ); +}; diff --git a/packages/main/views/DataSources/components/Header.tsx b/packages/main/views/DataSources/components/Header.tsx index de0ff105..9a938576 100644 --- a/packages/main/views/DataSources/components/Header.tsx +++ b/packages/main/views/DataSources/components/Header.tsx @@ -9,14 +9,16 @@ import useTheme from "@ui/theme/useTheme" export interface HeaderProps { title: string; datasource?: any; + onSave?: () => void } export function Header(props: HeaderProps) { + const navigate = useNavigate(); const theme = useTheme(); const urlLocation = useSelector((store: any) => store.urlLocation); const dispatch: any = useDispatch(); - const { title } = props; + const { title, onSave } = props; const isDsSaved = useSelector((store: any) => store.isDsSaved); const buttonMessage = useMemo(() => { if (isDsSaved) { @@ -61,7 +63,14 @@ export function Header(props: HeaderProps) {