From 26033f71afd6e313c722132a58a22aa99f78ae9e Mon Sep 17 00:00:00 2001 From: Alon Braymok <138359965+alonkeyval@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:52:44 +0300 Subject: [PATCH 1/2] Task 165 manage source (#368) --- frontend/webapp/app/layout.tsx | 4 + .../destinations/create/[id]/page.tsx | 111 ++++++++++++++++++ .../app/overview/destinations/create/page.tsx | 7 ++ .../app/overview/destinations/manage/page.tsx | 67 +++++++++++ .../webapp/app/overview/destinations/page.tsx | 15 ++- frontend/webapp/app/overview/layout.tsx | 6 +- .../app/overview/sources/create/page.tsx | 40 +++++++ .../app/overview/sources/manage/page.tsx | 103 ++++++++++++++++ .../app/overview/sources/manage/styled.tsx | 15 +++ frontend/webapp/app/overview/sources/page.tsx | 6 +- .../webapp/assets/icons/overview/index.tsx | 3 +- frontend/webapp/assets/icons/overview/pen.svg | 3 + .../manage.destination/manage.destination.tsx | 6 +- frontend/webapp/components/overview/index.tsx | 1 + .../sources.action.menu.styled.tsx | 1 + .../action.menu/sources.action.menu.tsx | 2 +- .../sources/delete.source/delete.source.tsx | 68 +++++++++++ .../manage.source.header.tsx | 96 +++++++++++++++ .../sources.manage.card.tsx | 4 +- .../sources.manage.list.tsx | 12 +- .../sources.manage.styled.tsx | 4 +- .../webapp/components/side.menu/menu/menu.tsx | 15 +-- .../destination/destination.styled.tsx | 10 -- .../overview/destination/destination.tsx | 94 +++------------ .../destination/new.destination.flow.tsx | 78 ++---------- .../destination/update.destination.flow.tsx | 8 +- frontend/webapp/containers/overview/index.tsx | 1 + .../overview/sources/manage.sources.tsx | 4 +- .../overview/sources/new.source.flow.tsx | 6 +- .../containers/overview/sources/sources.tsx | 62 ++-------- .../setup/destination/destination.section.tsx | 8 +- .../drop.down/drop.down.styled.tsx | 2 +- frontend/webapp/design.system/index.tsx | 1 + .../design.system/input/action.input.tsx | 42 +++++++ .../design.system/input/input.styled.tsx | 19 +++ .../notification/notification.tsx | 1 + .../search.input/search.input.styled.tsx | 2 +- .../webapp/design.system/text/text.styled.tsx | 2 +- frontend/webapp/services/sources.tsx | 12 +- frontend/webapp/utils/constants/index.tsx | 2 +- frontend/webapp/utils/constants/routes.tsx | 5 + frontend/webapp/utils/constants/string.tsx | 9 ++ 42 files changed, 713 insertions(+), 244 deletions(-) create mode 100644 frontend/webapp/app/overview/destinations/create/[id]/page.tsx create mode 100644 frontend/webapp/app/overview/destinations/create/page.tsx create mode 100644 frontend/webapp/app/overview/destinations/manage/page.tsx create mode 100644 frontend/webapp/app/overview/sources/create/page.tsx create mode 100644 frontend/webapp/app/overview/sources/manage/page.tsx create mode 100644 frontend/webapp/app/overview/sources/manage/styled.tsx create mode 100644 frontend/webapp/assets/icons/overview/pen.svg create mode 100644 frontend/webapp/components/overview/sources/delete.source/delete.source.tsx create mode 100644 frontend/webapp/components/overview/sources/manage.source.header/manage.source.header.tsx create mode 100644 frontend/webapp/design.system/input/action.input.tsx diff --git a/frontend/webapp/app/layout.tsx b/frontend/webapp/app/layout.tsx index efe4c8326..050b0c95c 100644 --- a/frontend/webapp/app/layout.tsx +++ b/frontend/webapp/app/layout.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ThemeProvider } from "styled-components"; import theme from "@/styles/palette"; import { QueryClient, QueryClientProvider } from "react-query"; +import Head from "next/head"; const LAYOUT_STYLE: React.CSSProperties = { margin: 0, @@ -30,6 +31,9 @@ export default function RootLayout({ + + Odigos + {children} diff --git a/frontend/webapp/app/overview/destinations/create/[id]/page.tsx b/frontend/webapp/app/overview/destinations/create/[id]/page.tsx new file mode 100644 index 000000000..f4082de12 --- /dev/null +++ b/frontend/webapp/app/overview/destinations/create/[id]/page.tsx @@ -0,0 +1,111 @@ +"use client"; +import React, { useEffect } from "react"; +import { NOTIFICATION, OVERVIEW, QUERIES } from "@/utils/constants"; +import { useMutation, useQuery } from "react-query"; +import { + getDestination, + getDestinationsTypes, + setDestination, +} from "@/services"; +import { ManageDestination, OverviewHeader } from "@/components/overview"; +import { useNotification, useSectionData } from "@/hooks"; +import { useRouter, useSearchParams } from "next/navigation"; +import { styled } from "styled-components"; + +const DEST = "dest"; + +const NewDestinationContainer = styled.div` + padding: 20px 36px; +`; + +export default function NewDestinationFlow() { + const { sectionData, setSectionData } = useSectionData(null); + const { show, Notification } = useNotification(); + const { mutate } = useMutation((body) => setDestination(body)); + const searchParams = useSearchParams(); + const router = useRouter(); + + const { data: destinationType } = useQuery( + [QUERIES.API_DESTINATION_TYPE, sectionData?.type], + () => getDestination(sectionData?.type), + { + enabled: !!sectionData, + } + ); + + const { data: destinationsList } = useQuery( + [QUERIES.API_DESTINATION_TYPES], + getDestinationsTypes + ); + + useEffect(onPageLoad, [destinationsList]); + + function onPageLoad() { + const search = searchParams.get(DEST); + if (!destinationsList || !search) return; + + let currentData = null; + + for (const category of destinationsList.categories) { + if (currentData) { + break; + } + const filterItem = category.items.filter(({ type }) => type === search); + if (filterItem.length) { + currentData = filterItem[0]; + } + } + + setSectionData(currentData); + } + + function onSuccess(message = OVERVIEW.DESTINATION_UPDATE_SUCCESS) { + show({ + type: NOTIFICATION.SUCCESS, + message, + }); + } + + function onError({ response }) { + const message = response?.data?.message; + show({ + type: NOTIFICATION.ERROR, + message, + }); + } + + function onSubmit(newDestination) { + const destination = { + ...newDestination, + type: sectionData.type, + }; + + mutate(destination, { + onSuccess: () => onSuccess(OVERVIEW.DESTINATION_CREATED_SUCCESS), + onError, + }); + } + + function handleBackPress() { + router.back(); + } + + return ( + <> + + {destinationType && sectionData && ( + + + + )} + + + ); +} diff --git a/frontend/webapp/app/overview/destinations/create/page.tsx b/frontend/webapp/app/overview/destinations/create/page.tsx new file mode 100644 index 000000000..3b9a92b41 --- /dev/null +++ b/frontend/webapp/app/overview/destinations/create/page.tsx @@ -0,0 +1,7 @@ +"use client"; +import React from "react"; +import { NewDestinationFlow } from "@/containers/overview"; + +export default function CreateDestinationPage() { + return ; +} diff --git a/frontend/webapp/app/overview/destinations/manage/page.tsx b/frontend/webapp/app/overview/destinations/manage/page.tsx new file mode 100644 index 000000000..cd92c828f --- /dev/null +++ b/frontend/webapp/app/overview/destinations/manage/page.tsx @@ -0,0 +1,67 @@ +"use client"; +import React, { useEffect, useState } from "react"; +import { NOTIFICATION, OVERVIEW, QUERIES } from "@/utils/constants"; +import { useNotification } from "@/hooks"; +import { useSearchParams } from "next/navigation"; +import UpdateDestinationFlow from "@/containers/overview/destination/update.destination.flow"; +import { getDestinations } from "@/services"; +import { useQuery } from "react-query"; +import { KeyvalLoader } from "@/design.system"; + +const DEST = "dest"; + +export default function ManageDestinationPage() { + const [selectedDestination, setSelectedDestination] = useState(null); + const { show, Notification } = useNotification(); + + const { + isLoading: destinationLoading, + data: destinationList, + refetch, + } = useQuery([QUERIES.API_DESTINATIONS], getDestinations); + + const searchParams = useSearchParams(); + + useEffect(onPageLoad, [searchParams, destinationList]); + + function onPageLoad() { + const search = searchParams.get(DEST); + const currentDestination = destinationList?.filter( + ({ id }) => id === search + ); + if (currentDestination?.length) { + setSelectedDestination(currentDestination[0]); + } + } + + function onSuccess(message = OVERVIEW.DESTINATION_UPDATE_SUCCESS) { + refetch(); + show({ + type: NOTIFICATION.SUCCESS, + message, + }); + } + + function onError({ response }) { + const message = response?.data?.message; + show({ + type: NOTIFICATION.ERROR, + message, + }); + } + + if (destinationLoading || !selectedDestination) { + return ; + } + + return ( + <> + + + + ); +} diff --git a/frontend/webapp/app/overview/destinations/page.tsx b/frontend/webapp/app/overview/destinations/page.tsx index 7056885ed..bb83b2d78 100644 --- a/frontend/webapp/app/overview/destinations/page.tsx +++ b/frontend/webapp/app/overview/destinations/page.tsx @@ -1,11 +1,22 @@ "use client"; import { DestinationContainer } from "@/containers/overview"; import React from "react"; +import { styled } from "styled-components"; + +const DestinationContainerWrapper = styled.div` + height: 100vh; + overflow-y: hidden; + ::-webkit-scrollbar { + display: none; + } + -ms-overflow-style: none; + scrollbar-width: none; +`; export default function DestinationDashboardPage() { return ( - <> + - + ); } diff --git a/frontend/webapp/app/overview/layout.tsx b/frontend/webapp/app/overview/layout.tsx index dc76e1c7f..2159907df 100644 --- a/frontend/webapp/app/overview/layout.tsx +++ b/frontend/webapp/app/overview/layout.tsx @@ -1,6 +1,7 @@ -"use client"; +// "use client"; import { Menu } from "@/components/side.menu"; import theme from "@/styles/palette"; +import { Metadata } from "next"; import React from "react"; const LAYOUT_STYLE = { @@ -14,6 +15,9 @@ const CHILDREN_STYLE = { width: "100%", height: "93%", }; +export const metadata: Metadata = { + title: "Odigos", +}; export default function Layout({ children }: { children: React.ReactNode }) { return ( diff --git a/frontend/webapp/app/overview/sources/create/page.tsx b/frontend/webapp/app/overview/sources/create/page.tsx new file mode 100644 index 000000000..9c83bfc82 --- /dev/null +++ b/frontend/webapp/app/overview/sources/create/page.tsx @@ -0,0 +1,40 @@ +"use client"; +import React from "react"; +import { NOTIFICATION, OVERVIEW, QUERIES } from "@/utils/constants"; +import { OverviewHeader } from "@/components/overview"; +import { useNotification } from "@/hooks"; +import { useQuery } from "react-query"; +import { getSources } from "@/services"; +import { NewSourceFlow } from "@/containers/overview/sources/new.source.flow"; +import { useRouter } from "next/navigation"; + +export default function CreateNewSourcesPage() { + const { show, Notification } = useNotification(); + const router = useRouter(); + const { data: sources, refetch } = useQuery( + [QUERIES.API_SOURCES], + getSources + ); + + function onNewSourceSuccess() { + setTimeout(() => { + router.back(); + refetch(); + }, 1000); + show({ + type: NOTIFICATION.SUCCESS, + message: OVERVIEW.SOURCE_CREATED_SUCCESS, + }); + } + + return ( + <> + router.back()} + /> + + + + ); +} diff --git a/frontend/webapp/app/overview/sources/manage/page.tsx b/frontend/webapp/app/overview/sources/manage/page.tsx new file mode 100644 index 000000000..a8de98f08 --- /dev/null +++ b/frontend/webapp/app/overview/sources/manage/page.tsx @@ -0,0 +1,103 @@ +"use client"; +import { ManageSourceHeader } from "@/components/overview/sources/manage.source.header/manage.source.header"; +import { getSources } from "@/services"; +import { + NOTIFICATION, + OVERVIEW, + QUERIES, + ROUTES, + SETUP, +} from "@/utils/constants"; +import { useRouter, useSearchParams } from "next/navigation"; +import React, { useEffect, useState } from "react"; +import { useMutation, useQuery } from "react-query"; +import { ManageSourcePageContainer, BackButtonWrapper } from "./styled"; +import { LANGUAGES_LOGOS } from "@/assets/images"; +import { Back } from "@/assets/icons/overview"; +import { KeyvalText } from "@/design.system"; +import { ManagedSource } from "@/types/sources"; +import { DeleteSource } from "@/components/overview"; +import { deleteSource } from "@/services/sources"; +import { useNotification } from "@/hooks"; + +const SOURCE = "source"; + +export default function ManageSourcePage() { + const [currentSource, setCurrentSource] = useState( + null + ); + const searchParams = useSearchParams(); + const router = useRouter(); + const { data: sources, refetch } = useQuery( + [QUERIES.API_SOURCES], + getSources + ); + const { show, Notification } = useNotification(); + const { mutate } = useMutation(() => + deleteSource( + currentSource?.namespace || "", + currentSource?.kind || "", + currentSource?.name || "" + ) + ); + useEffect(onPageLoad, [sources]); + + useEffect(() => { + console.log({ currentSource }); + }, [currentSource]); + + function onPageLoad() { + const search = searchParams.get(SOURCE); + const source = sources?.find((item) => item.name === search); + source && setCurrentSource(source); + } + function onError({ response }) { + const message = response?.data?.message; + show({ + type: NOTIFICATION.ERROR, + message, + }); + } + + function onSuccess() { + setTimeout(() => { + router.back(); + refetch(); + }, 1000); + show({ + type: NOTIFICATION.SUCCESS, + message: OVERVIEW.SOURCE_DELETED_SUCCESS, + }); + } + function onDelete() { + mutate(undefined, { + onSuccess, + onError, + }); + } + + return ( + + router.back()}> + + {SETUP.BACK} + + {currentSource && ( + + )} + + + + ); +} diff --git a/frontend/webapp/app/overview/sources/manage/styled.tsx b/frontend/webapp/app/overview/sources/manage/styled.tsx new file mode 100644 index 000000000..4face21f0 --- /dev/null +++ b/frontend/webapp/app/overview/sources/manage/styled.tsx @@ -0,0 +1,15 @@ +import styled from "styled-components"; + +export const ManageSourcePageContainer = styled.div` + padding: 32px; +`; + +export const BackButtonWrapper = styled.div` + display: flex; + width: fit-content; + align-items: center; + cursor: pointer; + p { + cursor: pointer !important; + } +`; diff --git a/frontend/webapp/app/overview/sources/page.tsx b/frontend/webapp/app/overview/sources/page.tsx index 454db1e18..77d0c32f2 100644 --- a/frontend/webapp/app/overview/sources/page.tsx +++ b/frontend/webapp/app/overview/sources/page.tsx @@ -3,9 +3,5 @@ import { SourcesContainer } from "@/containers/overview"; import React from "react"; export default function SourcesOverviewPage() { - return ( - <> - - - ); + return ; } diff --git a/frontend/webapp/assets/icons/overview/index.tsx b/frontend/webapp/assets/icons/overview/index.tsx index f9254c49d..68481e5ca 100644 --- a/frontend/webapp/assets/icons/overview/index.tsx +++ b/frontend/webapp/assets/icons/overview/index.tsx @@ -1,6 +1,7 @@ import KeyvalMiddleware from "./middleware.svg"; import Folder from "./folder.svg"; import Plus from "./plus.svg"; +import Pen from "./pen.svg"; import Back from "./back.svg"; -export { KeyvalMiddleware, Folder, Plus, Back }; +export { KeyvalMiddleware, Folder, Plus, Back, Pen }; diff --git a/frontend/webapp/assets/icons/overview/pen.svg b/frontend/webapp/assets/icons/overview/pen.svg new file mode 100644 index 000000000..03494bea2 --- /dev/null +++ b/frontend/webapp/assets/icons/overview/pen.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/webapp/components/overview/destination/manage.destination/manage.destination.tsx b/frontend/webapp/components/overview/destination/manage.destination/manage.destination.tsx index 51fd8d3cb..5dc79074a 100644 --- a/frontend/webapp/components/overview/destination/manage.destination/manage.destination.tsx +++ b/frontend/webapp/components/overview/destination/manage.destination/manage.destination.tsx @@ -25,9 +25,10 @@ const BackButtonWrapper = styled.div` } `; -const CreateConnectionWrapper = styled.div` +const CreateConnectionWrapper = styled.div<{ expand: boolean | undefined }>` display: flex; gap: 200px; + height: ${({ expand }) => (expand ? 630 : 530)}px; overflow: scroll; scrollbar-width: none; `; @@ -60,7 +61,8 @@ export function ManageDestination({ )} - + +
void; + name: string | undefined; + image_url: string; +}) { + const [showModal, setShowModal] = useState(false); + + const modalConfig = { + title: OVERVIEW.DELETE_SOURCE, + showHeader: true, + showOverlay: true, + positionX: ModalPositionX.center, + positionY: ModalPositionY.center, + padding: "20px", + footer: { + primaryBtnText: OVERVIEW.CONFIRM_SOURCE_DELETE, + primaryBtnAction: () => { + setShowModal(false); + onDelete(); + }, + }, + }; + + return ( + <> + + setShowModal(true)} + /> + + {showModal && ( + setShowModal(false)} + config={modalConfig} + > +
+ +
+ + {`${OVERVIEW.DELETE} ${name}`} + +
+ )} + + ); +} diff --git a/frontend/webapp/components/overview/sources/manage.source.header/manage.source.header.tsx b/frontend/webapp/components/overview/sources/manage.source.header/manage.source.header.tsx new file mode 100644 index 000000000..5fbcec042 --- /dev/null +++ b/frontend/webapp/components/overview/sources/manage.source.header/manage.source.header.tsx @@ -0,0 +1,96 @@ +import React, { useRef, useState } from "react"; +import styled from "styled-components"; +import { KeyvalActionInput, KeyvalImage, KeyvalText } from "@/design.system"; +import { Pen } from "@/assets/icons/overview"; +import { useOnClickOutside } from "@/hooks"; + +const ManageSourceHeaderWrapper = styled.div` + display: flex; + width: 100%; + min-width: 686px; + height: 104px; + align-items: center; + border-radius: 25px; + margin: 24px 0; + background: radial-gradient( + 78.09% 72.18% at 100% -0%, + rgba(150, 242, 255, 0.4) 0%, + rgba(150, 242, 255, 0) 61.91% + ), + linear-gradient(180deg, #2e4c55 0%, #303355 100%); +`; + +const TextWrapper = styled.div` + margin-left: 12px; + margin-right: 12px; +`; + +const EditIconWrapper = styled.div` + width: 20px; + height: 40px; + display: flex; + align-items: center; + + :hover { + cursor: pointer; + fill: ${({ theme }) => theme.colors.secondary}; + } +`; + +const ActionInputWrapper = styled.div` + width: 80%; + height: 49px; +`; + +const IMAGE_STYLE: React.CSSProperties = { + backgroundColor: "#fff", + padding: 4, + marginRight: 16, + marginLeft: 16, +}; + +export function ManageSourceHeader({ image_url, name }) { + const [showEditInput, setShowEditInput] = useState(true); + const [inputValue, setInputValue] = useState(name); + const containerRef = useRef(null); + const handleClickOutside = () => { + !showEditInput && handleSave(); + }; + + useOnClickOutside(containerRef, handleClickOutside); + + function handleSave() { + setShowEditInput(true); + } + + function handleInputChange(value) { + setInputValue(value); + } + + return ( + + + {showEditInput ? ( + <> + + + {name} + + + + setShowEditInput(false)}> + + + + ) : ( + + handleInputChange(e)} + onAction={handleSave} + /> + + )} + + ); +} diff --git a/frontend/webapp/components/overview/sources/sources.manage.list/sources.manage.card.tsx b/frontend/webapp/components/overview/sources/sources.manage.list/sources.manage.card.tsx index 1aa8f559b..a2a695f41 100644 --- a/frontend/webapp/components/overview/sources/sources.manage.list/sources.manage.card.tsx +++ b/frontend/webapp/components/overview/sources/sources.manage.list/sources.manage.card.tsx @@ -20,13 +20,15 @@ const LOGO_STYLE: React.CSSProperties = { interface SourceManagedCardProps { item: ManagedSource; + onClick?: () => void; } const DEPLOYMENT = "deployment"; export default function SourceManagedCard({ item = {} as ManagedSource, + onClick, }: SourceManagedCardProps) { return ( - + ( - + + router.push(`${ROUTES.MANAGE_SOURCE}?source=${source?.name}`) + } + /> )); } diff --git a/frontend/webapp/components/overview/sources/sources.manage.list/sources.manage.styled.tsx b/frontend/webapp/components/overview/sources/sources.manage.list/sources.manage.styled.tsx index 3fd4cad8d..9a36b4efa 100644 --- a/frontend/webapp/components/overview/sources/sources.manage.list/sources.manage.styled.tsx +++ b/frontend/webapp/components/overview/sources/sources.manage.list/sources.manage.styled.tsx @@ -12,10 +12,10 @@ export const CardWrapper = styled.div` align-items: center; flex-direction: column; gap: 10px; - /* cursor: pointer; + cursor: pointer; &:hover { background: var(--dark-mode-dark-1, #07111a81); - } */ + } `; export const EmptyListWrapper = styled.div` diff --git a/frontend/webapp/components/side.menu/menu/menu.tsx b/frontend/webapp/components/side.menu/menu/menu.tsx index 8f83912ec..814885343 100644 --- a/frontend/webapp/components/side.menu/menu/menu.tsx +++ b/frontend/webapp/components/side.menu/menu/menu.tsx @@ -4,7 +4,7 @@ import { MenuContainer, LogoWrapper, MenuItemsWrapper } from "./menu.styled"; import { KeyvalText } from "@/design.system"; import MenuItem from "../menu.item/menu.item"; import { useRouter } from "next/navigation"; -import { OVERVIEW } from "@/utils/constants"; +import { OVERVIEW, ROUTES } from "@/utils/constants"; import { MENU_ITEMS } from "./items"; export interface MenuItem { @@ -26,12 +26,13 @@ export function Menu() { useEffect(onLoad, []); function onLoad() { - const currentItem = MENU_ITEMS.find((item) => { - return item.navigate === window.location.pathname; - }); - if (currentItem?.id !== currentMenuItem.id) { - handleMenuItemClick(currentItem); - } + const currentItem = MENU_ITEMS.find( + ({ navigate }) => + navigate !== ROUTES.OVERVIEW && + window.location.pathname.includes(navigate) + ); + + currentItem && setCurrentMenuItem(currentItem); } function handleMenuItemClick(item) { diff --git a/frontend/webapp/containers/overview/destination/destination.styled.tsx b/frontend/webapp/containers/overview/destination/destination.styled.tsx index cac5196dd..008ad16f7 100644 --- a/frontend/webapp/containers/overview/destination/destination.styled.tsx +++ b/frontend/webapp/containers/overview/destination/destination.styled.tsx @@ -1,15 +1,5 @@ import styled from "styled-components"; -export const DestinationContainerWrapper = styled.div` - height: 100vh; - overflow-y: hidden; - ::-webkit-scrollbar { - display: none; - } - -ms-overflow-style: none; - scrollbar-width: none; -`; - export const NewDestinationContainer = styled.div` padding: 20px 36px; `; diff --git a/frontend/webapp/containers/overview/destination/destination.tsx b/frontend/webapp/containers/overview/destination/destination.tsx index 162b174a6..8ed985640 100644 --- a/frontend/webapp/containers/overview/destination/destination.tsx +++ b/frontend/webapp/containers/overview/destination/destination.tsx @@ -1,92 +1,34 @@ "use client"; -import React, { useState } from "react"; +import React from "react"; import { KeyvalLoader } from "@/design.system"; -import { NOTIFICATION, OVERVIEW, QUERIES } from "@/utils/constants"; +import { OVERVIEW, QUERIES, ROUTES } from "@/utils/constants"; import { useQuery } from "react-query"; import { getDestinations } from "@/services"; import { OverviewHeader, DestinationsManagedList } from "@/components/overview"; -import { DestinationContainerWrapper } from "./destination.styled"; -import { NewDestinationFlow } from "./new.destination.flow"; -import { UpdateDestinationFlow } from "./update.destination.flow"; -import { useNotification } from "@/hooks"; +import { useRouter } from "next/navigation"; export function DestinationContainer() { - const [selectedDestination, setSelectedDestination] = useState(null); - const [displayNewDestination, setDisplayNewDestination] = - useState(false); - const { show, Notification } = useNotification(); - const { - isLoading: destinationLoading, - data: destinationList, - refetch, - } = useQuery([QUERIES.API_DESTINATIONS], getDestinations); - - function onSuccess(message = OVERVIEW.DESTINATION_UPDATE_SUCCESS) { - refetch(); - setSelectedDestination(null); - setDisplayNewDestination(false); - show({ - type: NOTIFICATION.SUCCESS, - message, - }); - } - - function onError({ response }) { - const message = response?.data?.message; - show({ - type: NOTIFICATION.ERROR, - message, - }); - } - - function renderNewDestinationFlow() { - return ( - { - setDisplayNewDestination(false); - }} - /> - ); - } - - function renderUpdateDestinationFlow() { - return ( - - ); - } + const { isLoading: destinationLoading, data: destinationList } = useQuery( + [QUERIES.API_DESTINATIONS], + getDestinations + ); - function renderDestinationList() { - return ( - <> - - setDisplayNewDestination(true)} - /> - - ); - } + const router = useRouter(); if (destinationLoading) { return ; } return ( - - {displayNewDestination - ? renderNewDestinationFlow() - : selectedDestination - ? renderUpdateDestinationFlow() - : renderDestinationList()} - - + <> + + + router.push(`${ROUTES.UPDATE_DESTINATION}${id}`) + } + onMenuButtonClick={() => router.push(ROUTES.CREATE_DESTINATION)} + /> + ); } diff --git a/frontend/webapp/containers/overview/destination/new.destination.flow.tsx b/frontend/webapp/containers/overview/destination/new.destination.flow.tsx index 7a75a32c0..27c0dddc7 100644 --- a/frontend/webapp/containers/overview/destination/new.destination.flow.tsx +++ b/frontend/webapp/containers/overview/destination/new.destination.flow.tsx @@ -1,80 +1,26 @@ "use client"; -import React, { useState } from "react"; -import { OVERVIEW, QUERIES } from "@/utils/constants"; -import { useMutation, useQuery } from "react-query"; -import { getDestination, setDestination } from "@/services"; -import { ManageDestination, OverviewHeader } from "@/components/overview"; -import { useSectionData } from "@/hooks"; +import React from "react"; +import { OVERVIEW, ROUTES } from "@/utils/constants"; +import { OverviewHeader } from "@/components/overview"; import { DestinationSection } from "@/containers/setup/destination/destination.section"; import { NewDestinationContainer } from "./destination.styled"; +import { useRouter } from "next/navigation"; -export function NewDestinationFlow({ onBackClick, onSuccess, onError }) { - const { sectionData, setSectionData } = useSectionData(null); - const [managed, setManaged] = useState(null); - const { data: destinationType } = useQuery( - [QUERIES.API_DESTINATION_TYPE, sectionData?.type], - () => getDestination(sectionData?.type), - { - enabled: !!sectionData, - } - ); - const { mutate } = useMutation((body) => setDestination(body)); - - function onSubmit(newDestination) { - const destination = { - ...newDestination, - type: sectionData.type, - }; - - mutate(destination, { - onSuccess: () => onSuccess(OVERVIEW.DESTINATION_CREATED_SUCCESS), - onError, - }); - } - - function handleBackPress() { - if (managed && sectionData) { - setManaged(false); - setSectionData(null); - return; - } - onBackClick(); - } - - function renderNewDestinationForm() { - return ( - - ); - } - - function renderSelectNewDestination() { - return ( - <> - { - setSectionData(data); - setManaged(true); - }} - /> - - ); - } +export function NewDestinationFlow() { + const router = useRouter(); return ( <> router.back()} /> - {managed && sectionData - ? renderNewDestinationForm() - : renderSelectNewDestination()} + { + router.push(`${ROUTES.MANAGE_DESTINATION}${data.type}`); + }} + /> ); diff --git a/frontend/webapp/containers/overview/destination/update.destination.flow.tsx b/frontend/webapp/containers/overview/destination/update.destination.flow.tsx index 8eb710a29..d95fe7ac4 100644 --- a/frontend/webapp/containers/overview/destination/update.destination.flow.tsx +++ b/frontend/webapp/containers/overview/destination/update.destination.flow.tsx @@ -7,13 +7,15 @@ import { getDestination, updateDestination } from "@/services"; import { ManageDestination } from "@/components/overview"; import { deleteDestination } from "@/services/destinations"; import { ManageDestinationWrapper } from "./destination.styled"; +import { useRouter } from "next/navigation"; -export function UpdateDestinationFlow({ +export default function UpdateDestinationFlow({ selectedDestination, - setSelectedDestination, onSuccess, onError, }) { + const router = useRouter(); + const manageData = useMemo(() => { return { ...selectedDestination, @@ -60,7 +62,7 @@ export function UpdateDestinationFlow({ ) : ( setSelectedDestination(null)} + onBackClick={() => router.back()} destinationType={destinationType} selectedDestination={manageData} onSubmit={onSubmit} diff --git a/frontend/webapp/containers/overview/index.tsx b/frontend/webapp/containers/overview/index.tsx index 2a26e3504..e7895d4e4 100644 --- a/frontend/webapp/containers/overview/index.tsx +++ b/frontend/webapp/containers/overview/index.tsx @@ -1,3 +1,4 @@ export { OverviewContainer } from "./overview/overview"; export { DestinationContainer } from "./destination/destination"; export { SourcesContainer } from "./sources/sources"; +export { NewDestinationFlow } from "./destination/new.destination.flow"; diff --git a/frontend/webapp/containers/overview/sources/manage.sources.tsx b/frontend/webapp/containers/overview/sources/manage.sources.tsx index af0e0daa9..1b3339cac 100644 --- a/frontend/webapp/containers/overview/sources/manage.sources.tsx +++ b/frontend/webapp/containers/overview/sources/manage.sources.tsx @@ -9,7 +9,7 @@ import { ManagedSource, Namespace } from "@/types/sources"; const DEFAULT_FILTER = { name: "default", selected: false, totalApps: 0 }; -export function ManageSources({ setDisplayNewSourceFlow, sources }) { +export function ManageSources({ onAddClick, sources }) { const [searchFilter, setSearchFilter] = useState(""); const [currentNamespace, setCurrentNamespace] = useState(DEFAULT_FILTER); @@ -60,7 +60,7 @@ export function ManageSources({ setDisplayNewSourceFlow, sources }) { searchFilter={searchFilter} setSearchFilter={setSearchFilter} data={namespacesList} - onAddClick={() => setDisplayNewSourceFlow(true)} + onAddClick={onAddClick} setCurrentItem={setCurrentNamespace} /> diff --git a/frontend/webapp/containers/overview/sources/new.source.flow.tsx b/frontend/webapp/containers/overview/sources/new.source.flow.tsx index 5152767ba..3b5468b9a 100644 --- a/frontend/webapp/containers/overview/sources/new.source.flow.tsx +++ b/frontend/webapp/containers/overview/sources/new.source.flow.tsx @@ -17,7 +17,9 @@ export function NewSourceFlow({ onSuccess, sources }) { const { show, Notification } = useNotification(); function updateSectionDataWithSources() { - const sourceNamesSet = new Set(sources.map((source) => source.name)); + const sourceNamesSet = new Set( + sources.map((source: SelectedSources) => source.name) + ); const updatedSectionData: SelectedSources = {}; for (const key in sectionData) { @@ -50,6 +52,7 @@ export function NewSourceFlow({ onSuccess, sources }) { {`${totalSelected} ${SETUP.SELECTED}`} @@ -58,6 +61,7 @@ export function NewSourceFlow({ onSuccess, sources }) { + (null); - const { show, Notification } = useNotification(); - - const { data: sources, refetch } = useQuery( - [QUERIES.API_SOURCES], - getSources - ); - - useEffect(() => { - refetchSources(); - }, [displayNewSourceFlow]); - - async function refetchSources() { - if (displayNewSourceFlow === false) { - setTimeout(async () => { - refetch(); - }, 1000); - } - } - - function onNewSourceSuccess() { - setDisplayNewSourceFlow(false); - show({ - type: NOTIFICATION.SUCCESS, - message: OVERVIEW.SOURCE_CREATED_SUCCESS, - }); - } - - function renderNewSourceFlow() { - return ; - } - - function renderSources() { - return ( - - ); - } + const router = useRouter(); + const { data: sources } = useQuery([QUERIES.API_SOURCES], getSources); return ( - setDisplayNewSourceFlow(false) : null - } + + router.push(ROUTES.CREATE_SOURCE)} + sources={sources} /> - {displayNewSourceFlow ? renderNewSourceFlow() : renderSources()} - ); } diff --git a/frontend/webapp/containers/setup/destination/destination.section.tsx b/frontend/webapp/containers/setup/destination/destination.section.tsx index e8dd0a051..854edd779 100644 --- a/frontend/webapp/containers/setup/destination/destination.section.tsx +++ b/frontend/webapp/containers/setup/destination/destination.section.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import { useQuery } from "react-query"; -import { QUERIES, SETUP } from "@/utils/constants"; +import { NOTIFICATION, QUERIES, SETUP } from "@/utils/constants"; import { MONITORING_OPTIONS } from "@/components/setup/destination/utils"; import { DestinationList, DestinationOptionMenu } from "@/components/setup"; import Empty from "@/assets/images/empty-list.svg"; @@ -20,7 +20,7 @@ import { useNotification } from "@/hooks"; import { getDestinationsTypes } from "@/services"; type DestinationSectionProps = { - sectionData: any; + sectionData?: any; setSectionData: (data: any) => void; }; @@ -42,7 +42,7 @@ export function DestinationSection({ useEffect(() => { isError && show({ - type: "error", + type: NOTIFICATION.ERROR, message: error, }); }, [isError]); @@ -70,9 +70,9 @@ export function DestinationSection({ return ( displayItem && ( setSectionData(item)} /> ) diff --git a/frontend/webapp/design.system/drop.down/drop.down.styled.tsx b/frontend/webapp/design.system/drop.down/drop.down.styled.tsx index fccd64123..49282f3d6 100644 --- a/frontend/webapp/design.system/drop.down/drop.down.styled.tsx +++ b/frontend/webapp/design.system/drop.down/drop.down.styled.tsx @@ -32,7 +32,7 @@ export const DropdownHeader = styled.div` align-items: center; color: ${({ theme }) => theme.text.white}; font-size: 14px; - font-family: ${({ theme }) => theme.font_family.primary}; + font-family: ${({ theme }) => theme.font_family.primary}, sans-serif; font-weight: 400; `; diff --git a/frontend/webapp/design.system/index.tsx b/frontend/webapp/design.system/index.tsx index 7885d1a19..c1b3be3ce 100644 --- a/frontend/webapp/design.system/index.tsx +++ b/frontend/webapp/design.system/index.tsx @@ -15,6 +15,7 @@ export { KeyvalLink } from "./link/link"; export { KeyvalTooltip } from "./tooltip/tooltip"; export { KeyvalImage } from "./image/image"; export { KeyvalInput } from "./input/input"; +export { KeyvalActionInput } from "./input/action.input"; export { KeyvalVideo } from "./video/video"; export { KeyvalLoader } from "./loader/loader"; export { KeyvalNotification } from "./notification/notification"; diff --git a/frontend/webapp/design.system/input/action.input.tsx b/frontend/webapp/design.system/input/action.input.tsx new file mode 100644 index 000000000..4bede03d6 --- /dev/null +++ b/frontend/webapp/design.system/input/action.input.tsx @@ -0,0 +1,42 @@ +import React, { ChangeEvent } from "react"; +import { StyledActionInputContainer, StyledActionInput } from "./input.styled"; +import { KeyvalButton } from "../button/button"; +import { KeyvalText } from "../text/text"; +import theme from "@/styles/palette"; +import { ACTION } from "@/utils/constants"; + +interface InputProps { + value: string; + onAction: () => void; + onChange: (value: string) => void; + type?: string; + style?: React.CSSProperties; +} + +export function KeyvalActionInput({ + value, + onChange, + style = {}, +}: InputProps): JSX.Element { + function handleChange(event: ChangeEvent): void { + onChange(event.target.value); + } + + return ( + <> + + + + + + {ACTION.SAVE} + + + + + ); +} diff --git a/frontend/webapp/design.system/input/input.styled.tsx b/frontend/webapp/design.system/input/input.styled.tsx index 25b200005..808fdeffe 100644 --- a/frontend/webapp/design.system/input/input.styled.tsx +++ b/frontend/webapp/design.system/input/input.styled.tsx @@ -32,6 +32,19 @@ export const StyledInputContainer = styled.div` } `; +export const StyledActionInputContainer = styled.div` + position: relative; + display: flex; + width: 100%; + padding: 0px 12px; + height: 100%; + align-items: center; + justify-content: space-between; + gap: 10px; + border-radius: 4px; + border: ${({ theme }) => `1px solid ${theme.colors.secondary}`}; +`; + export const StyledInput = styled.input` background: transparent; border: none; @@ -40,6 +53,12 @@ export const StyledInput = styled.input` color: ${({ theme }) => theme.text.white}; `; +export const StyledActionInput = styled(StyledInput)` + color: var(--dark-mode-white, #fff); + font-family: Inter, sans-serif; + font-size: 24px; +`; + export const LabelWrapper = styled.div` margin-bottom: 8px; `; diff --git a/frontend/webapp/design.system/notification/notification.tsx b/frontend/webapp/design.system/notification/notification.tsx index a8d53e169..c0352b40e 100644 --- a/frontend/webapp/design.system/notification/notification.tsx +++ b/frontend/webapp/design.system/notification/notification.tsx @@ -7,6 +7,7 @@ import { KeyvalText } from "../text/text"; import CloseIcon from "@/assets/icons/X-blue.svg"; import SuccessIcon from "@/assets/icons/success-notification.svg"; import ErrorIcon from "@/assets/icons/error-notification.svg"; + interface KeyvalNotificationProps { type: "success" | "error" | "warning" | "info"; message: string; diff --git a/frontend/webapp/design.system/search.input/search.input.styled.tsx b/frontend/webapp/design.system/search.input/search.input.styled.tsx index f99e986d9..39ee4f362 100644 --- a/frontend/webapp/design.system/search.input/search.input.styled.tsx +++ b/frontend/webapp/design.system/search.input/search.input.styled.tsx @@ -29,7 +29,7 @@ export const StyledSearchInput = styled.input` color: ${({ active, theme }) => `${active ? theme.colors.white : theme.text.grey}`}; font-size: 14px; - font-family: ${({ theme }) => theme.font_family.primary}; + font-family: ${({ theme }) => theme.font_family.primary}, sans-serif; font-weight: 400; &:focus { color: ${({ theme }) => `solid 1px ${theme.colors.white}`}; diff --git a/frontend/webapp/design.system/text/text.styled.tsx b/frontend/webapp/design.system/text/text.styled.tsx index f400cfe94..a68573fc4 100644 --- a/frontend/webapp/design.system/text/text.styled.tsx +++ b/frontend/webapp/design.system/text/text.styled.tsx @@ -3,7 +3,7 @@ import styled from "styled-components"; export const TextWrapper = styled.p` color: ${({ theme }) => theme.text.white}; margin: 0; - font-family: ${({ theme }) => theme.font_family.primary}; + font-family: ${({ theme }) => theme.font_family.primary}, sans-serif; font-size: 16px; font-weight: 400; `; diff --git a/frontend/webapp/services/sources.tsx b/frontend/webapp/services/sources.tsx index eb50b72a2..fc7fd5050 100644 --- a/frontend/webapp/services/sources.tsx +++ b/frontend/webapp/services/sources.tsx @@ -1,5 +1,5 @@ import { API } from "@/utils/constants"; -import { get, post } from "./api"; +import { get, post, httpDelete } from "./api"; import { SelectedSources } from "@/types/sources"; export async function getNamespaces() { @@ -17,3 +17,13 @@ export async function setNamespaces(body: SelectedSources): Promise { export async function getSources() { return await get(API.SOURCES); } + +export async function deleteSource( + namespace: string, + kind: string, + name: string +) { + return await httpDelete( + `${API.SOURCES}/namespace/${namespace}/kind/${kind}/name/${name}` + ); +} diff --git a/frontend/webapp/utils/constants/index.tsx b/frontend/webapp/utils/constants/index.tsx index 11dd91a8d..90fdf2c71 100644 --- a/frontend/webapp/utils/constants/index.tsx +++ b/frontend/webapp/utils/constants/index.tsx @@ -1,4 +1,4 @@ export { ROUTES } from "./routes"; export { CONFIG } from "./config"; -export { SETUP, OVERVIEW, NOTIFICATION } from "./string"; +export { SETUP, OVERVIEW, NOTIFICATION, ACTION } from "./string"; export { API, QUERIES } from "./urls"; diff --git a/frontend/webapp/utils/constants/routes.tsx b/frontend/webapp/utils/constants/routes.tsx index a27e3f561..6a074d899 100644 --- a/frontend/webapp/utils/constants/routes.tsx +++ b/frontend/webapp/utils/constants/routes.tsx @@ -4,4 +4,9 @@ export const ROUTES = { SOURCES: "/overview/sources", DESTINATIONS: "/overview/destinations", NEW_DESTINATION: "/setup?state=destinations", + MANAGE_DESTINATION: "/overview/destinations/create/manage?dest=", + UPDATE_DESTINATION: "destinations/manage?dest=", + CREATE_DESTINATION: "destinations/create", + CREATE_SOURCE: "/overview/sources/create", + MANAGE_SOURCE: "/overview/sources/manage", }; diff --git a/frontend/webapp/utils/constants/string.tsx b/frontend/webapp/utils/constants/string.tsx index 53903e8c5..3227c2b95 100644 --- a/frontend/webapp/utils/constants/string.tsx +++ b/frontend/webapp/utils/constants/string.tsx @@ -73,13 +73,22 @@ export const OVERVIEW = { MANAGE: "Manage", DELETE: "Delete", DELETE_DESTINATION: "Delete Destination", + DELETE_SOURCE: "Delete Source", + SOURCE_DANGER_ZONE_TITLE: "Delete this source", + SOURCE_DANGER_ZONE_SUBTITLE: + "This action cannot be undone. This will permanently delete the source and all associated data.", DELETE_MODAL_TITLE: "Delete this destination", DELETE_MODAL_SUBTITLE: "This action cannot be undone. This will permanently delete the destination and all associated data.", DELETE_BUTTON: "I want to delete this destination", + CONFIRM_SOURCE_DELETE: "I want to delete this source", CONNECT: "Connect", }; +export const ACTION = { + SAVE: "Save", +}; + export const NOTIFICATION = { ERROR: "error", SUCCESS: "success", From bfb54d8888c7b9ee314e41527a620f6c0392e920 Mon Sep 17 00:00:00 2001 From: Alon Braymok <138359965+alonkeyval@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:46:21 +0300 Subject: [PATCH 2/2] Task 168 refactor (#370) --- .../destinations/create/[id]/page.tsx | 112 +----------------- .../app/overview/destinations/create/page.tsx | 2 - .../app/overview/destinations/manage/page.tsx | 66 +---------- .../webapp/app/overview/destinations/page.tsx | 1 - frontend/webapp/app/overview/layout.tsx | 7 +- frontend/webapp/app/setup/layout.tsx | 8 ++ .../destination/new.destination.form.tsx | 111 +++++++++++++++++ .../destination/update.destination.flow.tsx | 60 ++++++++-- frontend/webapp/containers/overview/index.tsx | 3 + .../containers/overview/overview/overview.tsx | 4 +- frontend/webapp/public/favicon.ico | Bin 25931 -> 0 bytes frontend/webapp/public/next.svg | 1 - frontend/webapp/public/vercel.svg | 1 - frontend/webapp/utils/constants/config.tsx | 5 + frontend/webapp/utils/constants/index.tsx | 2 +- 15 files changed, 190 insertions(+), 193 deletions(-) create mode 100644 frontend/webapp/app/setup/layout.tsx create mode 100644 frontend/webapp/containers/overview/destination/new.destination.form.tsx delete mode 100644 frontend/webapp/public/favicon.ico delete mode 100644 frontend/webapp/public/next.svg delete mode 100644 frontend/webapp/public/vercel.svg diff --git a/frontend/webapp/app/overview/destinations/create/[id]/page.tsx b/frontend/webapp/app/overview/destinations/create/[id]/page.tsx index f4082de12..0a4722ee6 100644 --- a/frontend/webapp/app/overview/destinations/create/[id]/page.tsx +++ b/frontend/webapp/app/overview/destinations/create/[id]/page.tsx @@ -1,111 +1,5 @@ -"use client"; -import React, { useEffect } from "react"; -import { NOTIFICATION, OVERVIEW, QUERIES } from "@/utils/constants"; -import { useMutation, useQuery } from "react-query"; -import { - getDestination, - getDestinationsTypes, - setDestination, -} from "@/services"; -import { ManageDestination, OverviewHeader } from "@/components/overview"; -import { useNotification, useSectionData } from "@/hooks"; -import { useRouter, useSearchParams } from "next/navigation"; -import { styled } from "styled-components"; +import { NewDestinationForm } from "@/containers/overview"; -const DEST = "dest"; - -const NewDestinationContainer = styled.div` - padding: 20px 36px; -`; - -export default function NewDestinationFlow() { - const { sectionData, setSectionData } = useSectionData(null); - const { show, Notification } = useNotification(); - const { mutate } = useMutation((body) => setDestination(body)); - const searchParams = useSearchParams(); - const router = useRouter(); - - const { data: destinationType } = useQuery( - [QUERIES.API_DESTINATION_TYPE, sectionData?.type], - () => getDestination(sectionData?.type), - { - enabled: !!sectionData, - } - ); - - const { data: destinationsList } = useQuery( - [QUERIES.API_DESTINATION_TYPES], - getDestinationsTypes - ); - - useEffect(onPageLoad, [destinationsList]); - - function onPageLoad() { - const search = searchParams.get(DEST); - if (!destinationsList || !search) return; - - let currentData = null; - - for (const category of destinationsList.categories) { - if (currentData) { - break; - } - const filterItem = category.items.filter(({ type }) => type === search); - if (filterItem.length) { - currentData = filterItem[0]; - } - } - - setSectionData(currentData); - } - - function onSuccess(message = OVERVIEW.DESTINATION_UPDATE_SUCCESS) { - show({ - type: NOTIFICATION.SUCCESS, - message, - }); - } - - function onError({ response }) { - const message = response?.data?.message; - show({ - type: NOTIFICATION.ERROR, - message, - }); - } - - function onSubmit(newDestination) { - const destination = { - ...newDestination, - type: sectionData.type, - }; - - mutate(destination, { - onSuccess: () => onSuccess(OVERVIEW.DESTINATION_CREATED_SUCCESS), - onError, - }); - } - - function handleBackPress() { - router.back(); - } - - return ( - <> - - {destinationType && sectionData && ( - - - - )} - - - ); +export default function CreateNewDestinationPage() { + return ; } diff --git a/frontend/webapp/app/overview/destinations/create/page.tsx b/frontend/webapp/app/overview/destinations/create/page.tsx index 3b9a92b41..3ec5946ca 100644 --- a/frontend/webapp/app/overview/destinations/create/page.tsx +++ b/frontend/webapp/app/overview/destinations/create/page.tsx @@ -1,5 +1,3 @@ -"use client"; -import React from "react"; import { NewDestinationFlow } from "@/containers/overview"; export default function CreateDestinationPage() { diff --git a/frontend/webapp/app/overview/destinations/manage/page.tsx b/frontend/webapp/app/overview/destinations/manage/page.tsx index cd92c828f..ebe6d6220 100644 --- a/frontend/webapp/app/overview/destinations/manage/page.tsx +++ b/frontend/webapp/app/overview/destinations/manage/page.tsx @@ -1,67 +1,5 @@ -"use client"; -import React, { useEffect, useState } from "react"; -import { NOTIFICATION, OVERVIEW, QUERIES } from "@/utils/constants"; -import { useNotification } from "@/hooks"; -import { useSearchParams } from "next/navigation"; -import UpdateDestinationFlow from "@/containers/overview/destination/update.destination.flow"; -import { getDestinations } from "@/services"; -import { useQuery } from "react-query"; -import { KeyvalLoader } from "@/design.system"; - -const DEST = "dest"; +import { UpdateDestinationFlow } from "@/containers/overview"; export default function ManageDestinationPage() { - const [selectedDestination, setSelectedDestination] = useState(null); - const { show, Notification } = useNotification(); - - const { - isLoading: destinationLoading, - data: destinationList, - refetch, - } = useQuery([QUERIES.API_DESTINATIONS], getDestinations); - - const searchParams = useSearchParams(); - - useEffect(onPageLoad, [searchParams, destinationList]); - - function onPageLoad() { - const search = searchParams.get(DEST); - const currentDestination = destinationList?.filter( - ({ id }) => id === search - ); - if (currentDestination?.length) { - setSelectedDestination(currentDestination[0]); - } - } - - function onSuccess(message = OVERVIEW.DESTINATION_UPDATE_SUCCESS) { - refetch(); - show({ - type: NOTIFICATION.SUCCESS, - message, - }); - } - - function onError({ response }) { - const message = response?.data?.message; - show({ - type: NOTIFICATION.ERROR, - message, - }); - } - - if (destinationLoading || !selectedDestination) { - return ; - } - - return ( - <> - - - - ); + return ; } diff --git a/frontend/webapp/app/overview/destinations/page.tsx b/frontend/webapp/app/overview/destinations/page.tsx index bb83b2d78..09f95a0aa 100644 --- a/frontend/webapp/app/overview/destinations/page.tsx +++ b/frontend/webapp/app/overview/destinations/page.tsx @@ -1,6 +1,5 @@ "use client"; import { DestinationContainer } from "@/containers/overview"; -import React from "react"; import { styled } from "styled-components"; const DestinationContainerWrapper = styled.div` diff --git a/frontend/webapp/app/overview/layout.tsx b/frontend/webapp/app/overview/layout.tsx index 2159907df..64ff4dd3b 100644 --- a/frontend/webapp/app/overview/layout.tsx +++ b/frontend/webapp/app/overview/layout.tsx @@ -1,6 +1,6 @@ -// "use client"; import { Menu } from "@/components/side.menu"; import theme from "@/styles/palette"; +import { METADATA } from "@/utils/constants"; import { Metadata } from "next"; import React from "react"; @@ -15,9 +15,8 @@ const CHILDREN_STYLE = { width: "100%", height: "93%", }; -export const metadata: Metadata = { - title: "Odigos", -}; + +export const metadata: Metadata = METADATA; export default function Layout({ children }: { children: React.ReactNode }) { return ( diff --git a/frontend/webapp/app/setup/layout.tsx b/frontend/webapp/app/setup/layout.tsx new file mode 100644 index 000000000..a4ee950c2 --- /dev/null +++ b/frontend/webapp/app/setup/layout.tsx @@ -0,0 +1,8 @@ +import { METADATA } from "@/utils/constants"; +import { Metadata } from "next"; + +export const metadata: Metadata = METADATA; + +export default function Layout({ children }: { children: React.ReactNode }) { + return
{children}
; +} diff --git a/frontend/webapp/containers/overview/destination/new.destination.form.tsx b/frontend/webapp/containers/overview/destination/new.destination.form.tsx new file mode 100644 index 000000000..c88928126 --- /dev/null +++ b/frontend/webapp/containers/overview/destination/new.destination.form.tsx @@ -0,0 +1,111 @@ +"use client"; +import React, { useEffect } from "react"; +import { NOTIFICATION, OVERVIEW, QUERIES } from "@/utils/constants"; +import { useMutation, useQuery } from "react-query"; +import { + getDestination, + getDestinationsTypes, + setDestination, +} from "@/services"; +import { ManageDestination, OverviewHeader } from "@/components/overview"; +import { useNotification, useSectionData } from "@/hooks"; +import { useRouter, useSearchParams } from "next/navigation"; +import { styled } from "styled-components"; + +const DEST = "dest"; + +const NewDestinationContainer = styled.div` + padding: 20px 36px; +`; + +export function NewDestinationForm() { + const { sectionData, setSectionData } = useSectionData(null); + const { show, Notification } = useNotification(); + const { mutate } = useMutation((body) => setDestination(body)); + const searchParams = useSearchParams(); + const router = useRouter(); + + const { data: destinationType } = useQuery( + [QUERIES.API_DESTINATION_TYPE, sectionData?.type], + () => getDestination(sectionData?.type), + { + enabled: !!sectionData, + } + ); + + const { data: destinationsList } = useQuery( + [QUERIES.API_DESTINATION_TYPES], + getDestinationsTypes + ); + + useEffect(onPageLoad, [destinationsList]); + + function onPageLoad() { + const search = searchParams.get(DEST); + if (!destinationsList || !search) return; + + let currentData = null; + + for (const category of destinationsList.categories) { + if (currentData) { + break; + } + const filterItem = category.items.filter(({ type }) => type === search); + if (filterItem.length) { + currentData = filterItem[0]; + } + } + + setSectionData(currentData); + } + + function onSuccess(message = OVERVIEW.DESTINATION_UPDATE_SUCCESS) { + show({ + type: NOTIFICATION.SUCCESS, + message, + }); + } + + function onError({ response }) { + const message = response?.data?.message; + show({ + type: NOTIFICATION.ERROR, + message, + }); + } + + function onSubmit(newDestination) { + const destination = { + ...newDestination, + type: sectionData.type, + }; + + mutate(destination, { + onSuccess: () => onSuccess(OVERVIEW.DESTINATION_CREATED_SUCCESS), + onError, + }); + } + + function handleBackPress() { + router.back(); + } + + return ( + <> + + {destinationType && sectionData && ( + + + + )} + + + ); +} diff --git a/frontend/webapp/containers/overview/destination/update.destination.flow.tsx b/frontend/webapp/containers/overview/destination/update.destination.flow.tsx index d95fe7ac4..66259fe3e 100644 --- a/frontend/webapp/containers/overview/destination/update.destination.flow.tsx +++ b/frontend/webapp/containers/overview/destination/update.destination.flow.tsx @@ -1,20 +1,22 @@ "use client"; -import React, { useMemo } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { KeyvalLoader } from "@/design.system"; -import { OVERVIEW, QUERIES } from "@/utils/constants"; +import { NOTIFICATION, OVERVIEW, QUERIES } from "@/utils/constants"; import { useMutation, useQuery } from "react-query"; import { getDestination, updateDestination } from "@/services"; import { ManageDestination } from "@/components/overview"; -import { deleteDestination } from "@/services/destinations"; +import { deleteDestination, getDestinations } from "@/services/destinations"; import { ManageDestinationWrapper } from "./destination.styled"; -import { useRouter } from "next/navigation"; +import { useRouter, useSearchParams } from "next/navigation"; +import { useNotification } from "@/hooks"; +const DEST = "dest"; + +export function UpdateDestinationFlow() { + const [selectedDestination, setSelectedDestination] = useState(null); -export default function UpdateDestinationFlow({ - selectedDestination, - onSuccess, - onError, -}) { const router = useRouter(); + const searchParams = useSearchParams(); + const { show, Notification } = useNotification(); const manageData = useMemo(() => { return { @@ -22,6 +24,7 @@ export default function UpdateDestinationFlow({ ...selectedDestination?.destination_type, }; }, [selectedDestination]); + const { isLoading: destinationTypeLoading, data: destinationType } = useQuery( [QUERIES.API_DESTINATION_TYPE, selectedDestination?.type], () => getDestination(selectedDestination?.type), @@ -30,6 +33,12 @@ export default function UpdateDestinationFlow({ } ); + const { + isLoading: destinationLoading, + data: destinationList, + refetch, + } = useQuery([QUERIES.API_DESTINATIONS], getDestinations); + const { mutate: handleUpdateDestination } = useMutation((body) => updateDestination(body, selectedDestination?.id) ); @@ -38,6 +47,8 @@ export default function UpdateDestinationFlow({ deleteDestination(selectedDestination?.id) ); + useEffect(onPageLoad, [searchParams, destinationList]); + function onDelete() { handleDeleteDestination(selectedDestination.id, { onSuccess: () => onSuccess(OVERVIEW.DESTINATION_DELETED_SUCCESS), @@ -57,6 +68,36 @@ export default function UpdateDestinationFlow({ }); } + function onPageLoad() { + const search = searchParams.get(DEST); + const currentDestination = destinationList?.filter( + ({ id }) => id === search + ); + if (currentDestination?.length) { + setSelectedDestination(currentDestination[0]); + } + } + + function onSuccess(message = OVERVIEW.DESTINATION_UPDATE_SUCCESS) { + refetch(); + show({ + type: NOTIFICATION.SUCCESS, + message, + }); + } + + function onError({ response }) { + const message = response?.data?.message; + show({ + type: NOTIFICATION.ERROR, + message, + }); + } + + if (destinationLoading || !selectedDestination) { + return ; + } + return destinationTypeLoading ? ( ) : ( @@ -68,6 +109,7 @@ export default function UpdateDestinationFlow({ onSubmit={onSubmit} onDelete={onDelete} /> +
); } diff --git a/frontend/webapp/containers/overview/index.tsx b/frontend/webapp/containers/overview/index.tsx index e7895d4e4..9c57b45c8 100644 --- a/frontend/webapp/containers/overview/index.tsx +++ b/frontend/webapp/containers/overview/index.tsx @@ -2,3 +2,6 @@ export { OverviewContainer } from "./overview/overview"; export { DestinationContainer } from "./destination/destination"; export { SourcesContainer } from "./sources/sources"; export { NewDestinationFlow } from "./destination/new.destination.flow"; +export { NewDestinationForm } from "./destination/new.destination.form"; +export { UpdateDestinationFlow } from "./destination/update.destination.flow"; + diff --git a/frontend/webapp/containers/overview/overview/overview.tsx b/frontend/webapp/containers/overview/overview/overview.tsx index 4be89af7f..04a979706 100644 --- a/frontend/webapp/containers/overview/overview/overview.tsx +++ b/frontend/webapp/containers/overview/overview/overview.tsx @@ -47,7 +47,9 @@ export function OverviewContainer() { containerHeight, destinations, "destination", - DESTINATION_NODE_HEIGHT, + destinations?.length > 1 + ? DESTINATION_NODE_HEIGHT + : NAMESPACE_NODE_HEIGHT, DESTINATION_NODE_POSITION ), [destinations, containerHeight] diff --git a/frontend/webapp/public/favicon.ico b/frontend/webapp/public/favicon.ico deleted file mode 100644 index 718d6fea4835ec2d246af9800eddb7ffb276240c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25931 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 LrJugUA?W`A8`#=m diff --git a/frontend/webapp/public/next.svg b/frontend/webapp/public/next.svg deleted file mode 100644 index 5174b28c5..000000000 --- a/frontend/webapp/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/webapp/public/vercel.svg b/frontend/webapp/public/vercel.svg deleted file mode 100644 index d2f842227..000000000 --- a/frontend/webapp/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/webapp/utils/constants/config.tsx b/frontend/webapp/utils/constants/config.tsx index f3aebd36f..0cda26a5d 100644 --- a/frontend/webapp/utils/constants/config.tsx +++ b/frontend/webapp/utils/constants/config.tsx @@ -3,3 +3,8 @@ export const CONFIG = { APPS_SELECTED: "APPS_SELECTED", FINISHED: "FINISHED", }; + +export const METADATA = { + title: "Odigos", + icons: "https://d2q89wckrml3k4.cloudfront.net/logo.png", +}; diff --git a/frontend/webapp/utils/constants/index.tsx b/frontend/webapp/utils/constants/index.tsx index 90fdf2c71..253c82b8a 100644 --- a/frontend/webapp/utils/constants/index.tsx +++ b/frontend/webapp/utils/constants/index.tsx @@ -1,4 +1,4 @@ export { ROUTES } from "./routes"; -export { CONFIG } from "./config"; +export { CONFIG, METADATA } from "./config"; export { SETUP, OVERVIEW, NOTIFICATION, ACTION } from "./string"; export { API, QUERIES } from "./urls";