From bf08cb08d2298780cf0b387579c7a95ad9bd714f Mon Sep 17 00:00:00 2001 From: Nicholas Bucher Date: Tue, 27 Aug 2024 16:50:19 -0400 Subject: [PATCH 01/75] changelog Signed-off-by: Nicholas Bucher --- changelog/v0.0.36/teams-page.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelog/v0.0.36/teams-page.yaml diff --git a/changelog/v0.0.36/teams-page.yaml b/changelog/v0.0.36/teams-page.yaml new file mode 100644 index 00000000..0361ce77 --- /dev/null +++ b/changelog/v0.0.36/teams-page.yaml @@ -0,0 +1,5 @@ +changelog: + - type: FIX + issueLink: https://github.com/solo-io/gloo-mesh-enterprise/issues/18336 + description: >- + Fixes an issue with the startup script where it didn't create the project/server/public folder. From b5d92744907033d3d93b1dbc953144bb21552f09 Mon Sep 17 00:00:00 2001 From: Nicholas Bucher Date: Tue, 27 Aug 2024 16:51:35 -0400 Subject: [PATCH 02/75] changelog Signed-off-by: Nicholas Bucher --- changelog/v0.0.36/teams-page.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/changelog/v0.0.36/teams-page.yaml b/changelog/v0.0.36/teams-page.yaml index 0361ce77..93a10681 100644 --- a/changelog/v0.0.36/teams-page.yaml +++ b/changelog/v0.0.36/teams-page.yaml @@ -1,5 +1,5 @@ changelog: - - type: FIX - issueLink: https://github.com/solo-io/gloo-mesh-enterprise/issues/18336 + - type: NEW_FEATURE + issueLink: https://github.com/solo-io/solo-projects/issues/6808 description: >- - Fixes an issue with the startup script where it didn't create the project/server/public folder. + Adds the teams page in to the gloo gateway version of the UI. From ac020854eb8bcc6c05631f57e69da282fd3f264f Mon Sep 17 00:00:00 2001 From: Nicholas Bucher Date: Thu, 5 Sep 2024 10:07:25 -0400 Subject: [PATCH 03/75] added existing portal server teams and apps and admin features Signed-off-by: Nicholas Bucher --- .../ApiProductDetailsPageHeading.tsx | 15 +- projects/ui/src/Components/Apis/ApisPage.tsx | 3 +- .../ui/src/Components/Apis/EmptyApisPage.tsx | 73 ++++++++ .../gloo-gateway-components/GG_ApisPage.tsx | 123 +++++++------ projects/ui/src/Components/AppContent.tsx | 2 +- .../ui/src/Components/AppContentRoutes.tsx | 171 ++++++++++-------- .../Details/Modals/NewSubscriptionModal.tsx | 5 +- .../AppSummaryCards/AppSummaryGridCard.tsx | 22 +-- .../ui/src/Components/Common/EmptyData.tsx | 2 +- .../Structure/BasicAuthVariant/Header.tsx | 154 ++++++++++++++++ .../HeaderSectionLoggedIn.tsx | 10 +- .../HeaderSectionLoggedOut.tsx | 17 +- .../ui/src/Components/Structure/Header.tsx | 156 ---------------- .../OidcAuthCodeHeaderDropdown.tsx | 2 +- .../Components/Teams/TeamsList/TeamsList.tsx | 4 +- projects/yarn.lock | 4 + 16 files changed, 427 insertions(+), 336 deletions(-) create mode 100644 projects/ui/src/Components/Apis/EmptyApisPage.tsx create mode 100644 projects/ui/src/Components/Structure/BasicAuthVariant/Header.tsx rename projects/ui/src/Components/Structure/{ => BasicAuthVariant}/HeaderSectionLoggedIn.tsx (91%) rename projects/ui/src/Components/Structure/{ => BasicAuthVariant}/HeaderSectionLoggedOut.tsx (92%) delete mode 100644 projects/ui/src/Components/Structure/Header.tsx create mode 100644 projects/yarn.lock diff --git a/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageHeading.tsx b/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageHeading.tsx index 8a2b832e..ba2c831a 100644 --- a/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageHeading.tsx +++ b/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageHeading.tsx @@ -1,4 +1,5 @@ import { Box, Flex, Select } from "@mantine/core"; +import { useContext, useState } from "react"; import toast from "react-hot-toast"; import { ApiProductSummary, @@ -6,12 +7,14 @@ import { ApiVersionSchema, } from "../../../Apis/api-types"; import { Icon } from "../../../Assets/Icons"; +import { AuthContext } from "../../../Context/AuthContext"; import { FormModalStyles } from "../../../Styles/shared/FormModalStyles"; import { useGetImageURL } from "../../../Utility/custom-image-utility"; import { downloadFile, filterMetadataToDisplay, } from "../../../Utility/utility"; +import NewSubscriptionModal from "../../Apps/Details/Modals/NewSubscriptionModal"; import { BannerHeading } from "../../Common/Banner/BannerHeading"; import { BannerHeadingTitle } from "../../Common/Banner/BannerHeadingTitle"; import { Button } from "../../Common/Button"; @@ -31,8 +34,8 @@ const ApiProductDetailsPageHeading = ({ onSelectedApiVersionChange: (newVersionId: string | null) => void; apiVersionSpec: ApiVersionSchema | undefined; }) => { - // const { isLoggedIn } = useContext(AuthContext); - // const [showSubscribeModal, setShowSubscribeModal] = useState(false); + const { isLoggedIn } = useContext(AuthContext); + const [showSubscribeModal, setShowSubscribeModal] = useState(false); const downloadApiSpec = () => { if (!selectedApiVersion?.apiSpec) { @@ -102,14 +105,12 @@ const ApiProductDetailsPageHeading = ({ /> )} - {/* - // Note: Removing sections for GGv2 demo. {isLoggedIn && ( - )} */} + )} + + + + ); +}; + +export default AddApiKeysSubSection; diff --git a/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx b/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx new file mode 100644 index 00000000..ab03c770 --- /dev/null +++ b/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx @@ -0,0 +1,137 @@ +import { Box, Flex } from "@mantine/core"; +import { useContext, useMemo, useState } from "react"; +import { di } from "react-magnetic-di"; +import { APIKey, App } from "../../../../Apis/api-types"; +import { + useListApiKeysForApp, + useListAppsForTeam, +} from "../../../../Apis/gg_hooks"; +import { AuthContext } from "../../../../Context/AuthContext"; +import { DetailsPageStyles } from "../../../../Styles/shared/DetailsPageStyles"; +import { GridCardStyles } from "../../../../Styles/shared/GridCard.style"; +import { UtilityStyles } from "../../../../Styles/shared/Utility.style"; +import { formatDateToMMDDYYYY } from "../../../../Utility/utility"; +import { Button } from "../../../Common/Button"; +import CustomPagination, { + pageOptions, + useCustomPagination, +} from "../../../Common/CustomPagination"; +import { SimpleEmptyContent } from "../../../Common/EmptyData"; +import { Loading } from "../../../Common/Loading"; +import Table from "../../../Common/Table"; +import ToggleAddButton from "../../../Common/ToggleAddButton"; +import ConfirmDeleteApiKeyModal from "../Modals/ConfirmDeleteApiKeyModal"; +import AddApiKeysSubSection from "./AddApiKeysSubSection"; + +const AppApiKeysSection = ({ app }: { app: App }) => { + di(useListAppsForTeam); + const { isAdmin } = useContext(AuthContext); + const { isLoading, data: apiKeys } = useListApiKeysForApp(app.id); + const [showAddApiKeySubSection, setShowAddApiKeySubSection] = useState(false); + + const customPaginationData = useCustomPagination( + apiKeys ?? [], + pageOptions.table + ); + const { paginatedData } = customPaginationData; + + const [confirmDeleteApiKey, setConfirmDeleteApiKey] = useState(); + + const rows = useMemo(() => { + return paginatedData?.map((apiKey) => { + return ( + ( + + {apiKey.name} + {formatDateToMMDDYYYY(new Date(apiKey.createdAt))} + {/* {JSON.stringify(apiKey.metadata)} */} + + + + + + + ) ?? [] + ); + }); + }, [paginatedData]); + + if (isLoading) { + return ; + } + return ( + + + API Keys + {!isAdmin && ( + + setShowAddApiKeySubSection(!showAddApiKeySubSection) + } + /> + )} + + setShowAddApiKeySubSection(false)} + /> + {!apiKeys?.length ? ( + // + + + {/* */} + + ) : ( + + + + + + + + + + + + {rows} + + + + + +
NameCreated + + Delete + +
+ + + +
+
+
+
+ )} + setConfirmDeleteApiKey(undefined)} + /> +
+ ); +}; + +export default AppApiKeysSection; diff --git a/projects/ui/src/Components/Apps/Details/AppDetailsPageContent.tsx b/projects/ui/src/Components/Apps/Details/AppDetailsPageContent.tsx index 11575485..df042716 100644 --- a/projects/ui/src/Components/Apps/Details/AppDetailsPageContent.tsx +++ b/projects/ui/src/Components/Apps/Details/AppDetailsPageContent.tsx @@ -1,19 +1,34 @@ -import { Box, Flex, Loader } from "@mantine/core"; +import { Box, Flex, Loader, Tooltip } from "@mantine/core"; +import { useMemo } from "react"; import { di } from "react-magnetic-di"; +import { NavLink } from "react-router-dom"; import { App } from "../../../Apis/api-types"; -import { useListSubscriptionsForApp } from "../../../Apis/gg_hooks"; +import { + useListSubscriptionsForApp, + useListTeams, +} from "../../../Apis/gg_hooks"; +import { Icon } from "../../../Assets/Icons"; +import { UtilityStyles } from "../../../Styles/shared/Utility.style"; +import { getTeamDetailsLink } from "../../../Utility/link-builders"; import { BannerHeading } from "../../Common/Banner/BannerHeading"; import { BannerHeadingTitle } from "../../Common/Banner/BannerHeadingTitle"; import { PageContainer } from "../../Common/PageContainer"; +import AppApiKeysSection from "./ApiKeysSection/AppApiKeysSection"; import AppApiSubscriptionsSection from "./ApiSubscriptionsSection/AppApiSubscriptionsSection"; import AppAuthenticationSection from "./AuthenticationSection/AppAuthenticationSection"; import EditAppButtonWithModal from "./EditAppButtonWithModal"; export const AppDetailsPageContent = ({ app }: { app: App }) => { - di(useListSubscriptionsForApp); + di(useListSubscriptionsForApp, useListTeams); const { isLoading: isLoadingSubscriptions, data: subscriptions } = useListSubscriptionsForApp(app.id); + const { isLoading: isLoadingTeams, data: teams } = useListTeams(); + const team = useMemo( + () => teams?.find((t) => t.id === app.teamId), + [teams, app] + ); + // Mock data for testing // app.idpClientId = "4df81266-f855-466d-8ded-699056780850"; // app.idpClientName = "test-idp"; @@ -27,6 +42,7 @@ export const AppDetailsPageContent = ({ app }: { app: App }) => { title={ } stylingTweaks={{ fontSize: "32px", lineHeight: "36px", @@ -34,7 +50,31 @@ export const AppDetailsPageContent = ({ app }: { app: App }) => { additionalInfo={} /> } - description={app.description} + description={ + <> + {!!team && !!team.name && ( + + + + + + {team?.name} + + + + + )} + {app.description} + + } breadcrumbItems={[ { label: "Home", link: "/" }, { label: "Apps", link: "/apps" }, @@ -44,6 +84,9 @@ export const AppDetailsPageContent = ({ app }: { app: App }) => { {appHasOAuthClient && } + + + {isLoadingSubscriptions || subscriptions === undefined ? ( ) : ( diff --git a/projects/ui/src/Components/Apps/Details/Modals/ConfirmDeleteApiKeyModal.tsx b/projects/ui/src/Components/Apps/Details/Modals/ConfirmDeleteApiKeyModal.tsx new file mode 100644 index 00000000..4d01a8e8 --- /dev/null +++ b/projects/ui/src/Components/Apps/Details/Modals/ConfirmDeleteApiKeyModal.tsx @@ -0,0 +1,61 @@ +import { Box, CloseButton, Flex } from "@mantine/core"; +import { FormEvent } from "react"; +import toast from "react-hot-toast"; +import { di } from "react-magnetic-di"; +import { useDeleteApiKeyMutation } from "../../../../Apis/gg_hooks"; +import { FormModalStyles } from "../../../../Styles/shared/FormModalStyles"; +import { Button } from "../../../Common/Button"; + +const ConfirmDeleteApiKeyModal = ({ + apiKeyId, + appId, + open, + onClose, +}: { + apiKeyId: string; + appId: string; + open: boolean; + onClose: () => void; +}) => { + di(useDeleteApiKeyMutation); + const { trigger: deleteApiKey } = useDeleteApiKeyMutation(appId); + const onConfirm = async (e?: FormEvent) => { + e?.preventDefault(); + await toast.promise(deleteApiKey({ apiKeyId }), { + error: (e) => "There was an error deleting the API Key. " + e, + loading: "Deleting the API Key...", + success: "Deleted the API Key!", + }); + onClose(); + }; + + // + // Render + // + return ( + + +
+ Delete API Key + + Are you sure that you want to delete this API Key? + +
+ +
+ + + + + + + +
+ ); +}; + +export default ConfirmDeleteApiKeyModal; diff --git a/projects/ui/src/Components/Common/EmptyData.tsx b/projects/ui/src/Components/Common/EmptyData.tsx index ca9135e1..d0659f91 100644 --- a/projects/ui/src/Components/Common/EmptyData.tsx +++ b/projects/ui/src/Components/Common/EmptyData.tsx @@ -1,6 +1,7 @@ import { css } from "@emotion/react"; import styled from "@emotion/styled"; import { Box, Flex, Text } from "@mantine/core"; +import { borderRadiusConstants } from "../../Styles/constants"; const StyledEmptyContentOuter = styled.div( ({ theme }) => css` @@ -8,7 +9,12 @@ const StyledEmptyContentOuter = styled.div( justify-content: center; text-align: center; line-height: 2rem; - background-color: ${theme.marchGrey}; + /* background-color: ${theme.splashBlueLight7}; */ + background-color: white; + box-shadow: 1px 1px 5px ${theme.splashBlue}; + border: 1px solid ${theme.splashBlue}; + border-radius: ${borderRadiusConstants.small}; + margin-bottom: 30px; padding: 30px; ` ); @@ -26,14 +32,18 @@ export const SimpleEmptyContent = (props: { {props.title && ( {props.title} )} - {props.children} + {!!props.children && ( + + {props.children} + + )}
); diff --git a/projects/ui/src/Components/Teams/Details/TeamDetailsPageContent.tsx b/projects/ui/src/Components/Teams/Details/TeamDetailsPageContent.tsx index e1494227..8c600b02 100644 --- a/projects/ui/src/Components/Teams/Details/TeamDetailsPageContent.tsx +++ b/projects/ui/src/Components/Teams/Details/TeamDetailsPageContent.tsx @@ -1,6 +1,7 @@ import { Box, Flex } from "@mantine/core"; import { useContext } from "react"; import { Team } from "../../../Apis/api-types"; +import { Icon } from "../../../Assets/Icons"; import { AuthContext } from "../../../Context/AuthContext"; import { BannerHeading } from "../../Common/Banner/BannerHeading"; import { BannerHeadingTitle } from "../../Common/Banner/BannerHeadingTitle"; @@ -17,6 +18,7 @@ const TeamDetailsPageContent = ({ team }: { team: Team }) => { title={ } stylingTweaks={{ fontSize: "32px", lineHeight: "36px", diff --git a/projects/ui/src/Styles/colors.ts b/projects/ui/src/Styles/colors.ts index 06513481..d8c35710 100644 --- a/projects/ui/src/Styles/colors.ts +++ b/projects/ui/src/Styles/colors.ts @@ -43,6 +43,8 @@ const baseColors = { const colorMap = { ...baseColors, + januaryGreyDark1: Color(baseColors.januaryGrey).darken(0.01).hex(), + marchGreyDark3: Color(baseColors.marchGrey).darken(0.03).hex(), marchGreyDark5: Color(baseColors.marchGrey).darken(0.05).hex(), marchGreyDark10: Color(baseColors.marchGrey).darken(0.1).hex(), diff --git a/projects/ui/src/Styles/global-styles/mantine-overrides.style.ts b/projects/ui/src/Styles/global-styles/mantine-overrides.style.ts index e020250e..4eb8c2fc 100644 --- a/projects/ui/src/Styles/global-styles/mantine-overrides.style.ts +++ b/projects/ui/src/Styles/global-styles/mantine-overrides.style.ts @@ -63,4 +63,8 @@ export const mantineGlobalStyles = css` } } } + + code.mantine-Code-root { + background-color: ${colors.januaryGreyDark1}; + } `; From 9c771188097682fd43b68ac6dd1042ed82e74d71 Mon Sep 17 00:00:00 2001 From: Nicholas Bucher Date: Wed, 11 Sep 2024 10:43:22 -0400 Subject: [PATCH 16/75] updated empty state, added some instructions for empty states. Signed-off-by: Nicholas Bucher --- .../ApiProductDetailsPageBody.tsx | 1 - .../SchemaTab/SchemaTabContent.tsx | 29 +++++++------- .../ApisTab/ApisList.tsx | 9 ++++- .../gloo-mesh-gateway-components/ApisList.tsx | 6 ++- .../ApiKeysSection/AppApiKeysSection.tsx | 4 +- .../AppApiSubscriptionsSection.tsx | 6 +-- .../Apps/Details/AppDetailsPageContent.tsx | 2 +- .../Components/Apps/PageContent/AppsList.tsx | 9 ++++- .../ui/src/Components/Common/EmptyData.tsx | 39 +------------------ .../SubscriptionsList/SubscriptionsList.tsx | 4 +- .../Details/AppsSection/TeamAppsSection.tsx | 4 +- .../Details/UsersSection/TeamUsersSection.tsx | 5 ++- .../Components/Teams/TeamsList/TeamsList.tsx | 6 +-- .../UsagePlanList/APIUsagePlansList.tsx | 4 +- 14 files changed, 51 insertions(+), 77 deletions(-) diff --git a/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageBody.tsx b/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageBody.tsx index b3285d25..bcaca627 100644 --- a/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageBody.tsx +++ b/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageBody.tsx @@ -71,7 +71,6 @@ export function ApiProductDetailsPageBody({ */} - + + Add a version to the spec.versions field of this{" "} + ApiProduct for data to appear. + ); } @@ -36,9 +31,13 @@ const SchemaTabContent = ({ // There is a selected API version, but no schema. return ( - + + The schema was not returned for this ApiProduct version. +
+ Verify that your OpenApi spec was generated correctly in the + corresponding ApiDoc resource for this{" "} + Service. +
); } diff --git a/projects/ui/src/Components/Apis/gloo-gateway-components/ApisTab/ApisList.tsx b/projects/ui/src/Components/Apis/gloo-gateway-components/ApisTab/ApisList.tsx index 7e8d8f4d..83a5ac36 100644 --- a/projects/ui/src/Components/Apis/gloo-gateway-components/ApisTab/ApisList.tsx +++ b/projects/ui/src/Components/Apis/gloo-gateway-components/ApisTab/ApisList.tsx @@ -12,7 +12,7 @@ import CustomPagination, { pageOptions, useCustomPagination, } from "../../../Common/CustomPagination"; -import { EmptyData } from "../../../Common/EmptyData"; +import { SimpleEmptyContent } from "../../../Common/EmptyData"; import { Loading } from "../../../Common/Loading"; import { ApisPageStyles } from "../../ApisPage.style"; import { ApiSummaryGridCard } from "./ApiSummaryCards/ApiSummaryGridCard"; @@ -78,8 +78,13 @@ export function ApisList({ if (apiProductsList === undefined) { return ; } + if (!apiProductsList.length) { + return ; + } if (!filteredApiProductsList.length) { - return ; + return ( + + ); } if (preferGridView) { return ( diff --git a/projects/ui/src/Components/Apis/gloo-mesh-gateway-components/ApisList.tsx b/projects/ui/src/Components/Apis/gloo-mesh-gateway-components/ApisList.tsx index 46d5f7c0..3a2a2921 100644 --- a/projects/ui/src/Components/Apis/gloo-mesh-gateway-components/ApisList.tsx +++ b/projects/ui/src/Components/Apis/gloo-mesh-gateway-components/ApisList.tsx @@ -7,7 +7,7 @@ import CustomPagination, { pageOptions, useCustomPagination, } from "../../Common/CustomPagination"; -import { EmptyData } from "../../Common/EmptyData"; +import { SimpleEmptyContent } from "../../Common/EmptyData"; import { Loading } from "../../Common/Loading"; import { ApiSummaryGridCard } from "./ApiSummaryGridCard"; import { ApiSummaryListCard } from "./ApiSummaryListCard"; @@ -72,7 +72,9 @@ export function ApisList({ } if (!displayedApisList.length) { - return ; + return ( + + ); } return ( <> diff --git a/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx b/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx index ab03c770..2e145992 100644 --- a/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx +++ b/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx @@ -86,10 +86,8 @@ const AppApiKeysSection = ({ app }: { app: App }) => { onClose={() => setShowAddApiKeySubSection(false)} /> {!apiKeys?.length ? ( - // - - {/* */} + ) : ( diff --git a/projects/ui/src/Components/Apps/Details/ApiSubscriptionsSection/AppApiSubscriptionsSection.tsx b/projects/ui/src/Components/Apps/Details/ApiSubscriptionsSection/AppApiSubscriptionsSection.tsx index 0dc43e45..4155066b 100644 --- a/projects/ui/src/Components/Apps/Details/ApiSubscriptionsSection/AppApiSubscriptionsSection.tsx +++ b/projects/ui/src/Components/Apps/Details/ApiSubscriptionsSection/AppApiSubscriptionsSection.tsx @@ -5,7 +5,7 @@ import { Icon } from "../../../../Assets/Icons"; import { DetailsPageStyles } from "../../../../Styles/shared/DetailsPageStyles"; import { UtilityStyles } from "../../../../Styles/shared/Utility.style"; import { Button } from "../../../Common/Button"; -import { EmptyData } from "../../../Common/EmptyData"; +import { SimpleEmptyContent } from "../../../Common/EmptyData"; import SubscriptionInfoCard from "../../../Common/SubscriptionsList/SubscriptionInfoCard/SubscriptionInfoCard"; import NewSubscriptionModal from "../Modals/NewSubscriptionModal"; @@ -43,8 +43,8 @@ const AppApiSubscriptionsSection = ({ /> {subscriptions.length === 0 && ( - - + + )} diff --git a/projects/ui/src/Components/Apps/Details/AppDetailsPageContent.tsx b/projects/ui/src/Components/Apps/Details/AppDetailsPageContent.tsx index df042716..a4b2a4a2 100644 --- a/projects/ui/src/Components/Apps/Details/AppDetailsPageContent.tsx +++ b/projects/ui/src/Components/Apps/Details/AppDetailsPageContent.tsx @@ -23,7 +23,7 @@ export const AppDetailsPageContent = ({ app }: { app: App }) => { const { isLoading: isLoadingSubscriptions, data: subscriptions } = useListSubscriptionsForApp(app.id); - const { isLoading: isLoadingTeams, data: teams } = useListTeams(); + const { data: teams } = useListTeams(); const team = useMemo( () => teams?.find((t) => t.id === app.teamId), [teams, app] diff --git a/projects/ui/src/Components/Apps/PageContent/AppsList.tsx b/projects/ui/src/Components/Apps/PageContent/AppsList.tsx index 7e8ee4fe..c0b49191 100644 --- a/projects/ui/src/Components/Apps/PageContent/AppsList.tsx +++ b/projects/ui/src/Components/Apps/PageContent/AppsList.tsx @@ -4,7 +4,7 @@ import { App, Team } from "../../../Apis/api-types"; import { useListAppsForTeams } from "../../../Apis/gg_hooks"; import { FilterPair, FilterType } from "../../../Utility/filter-utility"; import { omitErrorMessageResponse } from "../../../Utility/utility"; -import { EmptyData } from "../../Common/EmptyData"; +import { SimpleEmptyContent } from "../../Common/EmptyData"; import { Loading } from "../../Common/Loading"; import { AppsPageStyles } from "../AppsPage.style"; import { AppSummaryGridCard } from "./AppSummaryCards/AppSummaryGridCard"; @@ -85,8 +85,13 @@ export function AppsList({ if (isLoading) { return ; } + if (!appsList?.length) { + return ; + } if (!filteredAppsList.length) { - return ; + return ( + + ); } return ( diff --git a/projects/ui/src/Components/Common/EmptyData.tsx b/projects/ui/src/Components/Common/EmptyData.tsx index d0659f91..54a2031e 100644 --- a/projects/ui/src/Components/Common/EmptyData.tsx +++ b/projects/ui/src/Components/Common/EmptyData.tsx @@ -1,6 +1,6 @@ import { css } from "@emotion/react"; import styled from "@emotion/styled"; -import { Box, Flex, Text } from "@mantine/core"; +import { Box } from "@mantine/core"; import { borderRadiusConstants } from "../../Styles/constants"; const StyledEmptyContentOuter = styled.div( @@ -9,7 +9,6 @@ const StyledEmptyContentOuter = styled.div( justify-content: center; text-align: center; line-height: 2rem; - /* background-color: ${theme.splashBlueLight7}; */ background-color: white; box-shadow: 1px 1px 5px ${theme.splashBlue}; border: 1px solid ${theme.splashBlue}; @@ -19,9 +18,6 @@ const StyledEmptyContentOuter = styled.div( ` ); -/** - * This is typically used for Empty sections with more custom content. - */ export const SimpleEmptyContent = (props: { children?: React.ReactNode; title?: React.ReactNode; @@ -40,7 +36,7 @@ export const SimpleEmptyContent = (props: { )} {!!props.children && ( - + {props.children} )} @@ -48,34 +44,3 @@ export const SimpleEmptyContent = (props: { ); }; - -/** - * This is typically used for Empty data for topics. - */ -export function EmptyData( - props: - | { - topic: string; - message?: string; - } - | { - topicMessageOverride: React.ReactNode; - } -) { - return ( - - - {"topicMessageOverride" in props ? ( - <>{props.topicMessageOverride} - ) : ( - <>No {props.topic} results were found - )} - - {"message" in props && !!props.message && ( - - {props.message} - - )} - - ); -} diff --git a/projects/ui/src/Components/Common/SubscriptionsList/SubscriptionsList.tsx b/projects/ui/src/Components/Common/SubscriptionsList/SubscriptionsList.tsx index 14328fb1..9479c885 100644 --- a/projects/ui/src/Components/Common/SubscriptionsList/SubscriptionsList.tsx +++ b/projects/ui/src/Components/Common/SubscriptionsList/SubscriptionsList.tsx @@ -5,7 +5,7 @@ import { isSubscriptionsListError, } from "../../../Apis/api-types"; import { colors } from "../../../Styles"; -import { EmptyData } from "../../Common/EmptyData"; +import { SimpleEmptyContent } from "../../Common/EmptyData"; import { FiltrationProp } from "../Filters/AppliedFiltersSection"; import SubscriptionInfoCard from "./SubscriptionInfoCard/SubscriptionInfoCard"; @@ -35,7 +35,7 @@ const SubscriptionsList = ({ return null; } if (subscriptions.length === 0) { - return ; + return ; } return ( diff --git a/projects/ui/src/Components/Teams/Details/AppsSection/TeamAppsSection.tsx b/projects/ui/src/Components/Teams/Details/AppsSection/TeamAppsSection.tsx index 39515fd9..96a81dd0 100644 --- a/projects/ui/src/Components/Teams/Details/AppsSection/TeamAppsSection.tsx +++ b/projects/ui/src/Components/Teams/Details/AppsSection/TeamAppsSection.tsx @@ -14,7 +14,7 @@ import CustomPagination, { pageOptions, useCustomPagination, } from "../../../Common/CustomPagination"; -import { EmptyData } from "../../../Common/EmptyData"; +import { SimpleEmptyContent } from "../../../Common/EmptyData"; import { Loading } from "../../../Common/Loading"; import Table from "../../../Common/Table"; import ToggleAddButton from "../../../Common/ToggleAddButton"; @@ -86,7 +86,7 @@ const TeamAppsSection = ({ team }: { team: Team }) => { )} {!apps?.length ? ( - + ) : ( diff --git a/projects/ui/src/Components/Teams/Details/UsersSection/TeamUsersSection.tsx b/projects/ui/src/Components/Teams/Details/UsersSection/TeamUsersSection.tsx index 12bf55a9..f0cc1060 100644 --- a/projects/ui/src/Components/Teams/Details/UsersSection/TeamUsersSection.tsx +++ b/projects/ui/src/Components/Teams/Details/UsersSection/TeamUsersSection.tsx @@ -16,7 +16,7 @@ import CustomPagination, { pageOptions, useCustomPagination, } from "../../../Common/CustomPagination"; -import { EmptyData } from "../../../Common/EmptyData"; +import { SimpleEmptyContent } from "../../../Common/EmptyData"; import { Loading } from "../../../Common/Loading"; import Table from "../../../Common/Table"; import ToggleAddButton from "../../../Common/ToggleAddButton"; @@ -100,7 +100,8 @@ const TeamUsersSection = ({ team }: { team: Team }) => { /> {!members?.length ? ( - + {/* We never should get here, since the user must be a member. */} + ) : ( diff --git a/projects/ui/src/Components/Teams/TeamsList/TeamsList.tsx b/projects/ui/src/Components/Teams/TeamsList/TeamsList.tsx index 119914c6..5bedf4ce 100644 --- a/projects/ui/src/Components/Teams/TeamsList/TeamsList.tsx +++ b/projects/ui/src/Components/Teams/TeamsList/TeamsList.tsx @@ -1,7 +1,7 @@ import { Box, Flex } from "@mantine/core"; import { di } from "react-magnetic-di"; import { useListTeams } from "../../../Apis/gg_hooks"; -import { EmptyData } from "../../Common/EmptyData"; +import { SimpleEmptyContent } from "../../Common/EmptyData"; import { Loading } from "../../Common/Loading"; import { TeamSummaryGridCard } from "./TeamSummaryCards/TeamSummaryGridCard"; @@ -15,8 +15,8 @@ export function TeamsList() { if (teamsList === undefined || isLoading) { return ; } - if (!teamsList.length) { - return ; + if (!teamsList?.length) { + return ; } return ( diff --git a/projects/ui/src/Components/UsagePlans/UsagePlanList/APIUsagePlansList.tsx b/projects/ui/src/Components/UsagePlans/UsagePlanList/APIUsagePlansList.tsx index 0cd03c09..bb93abbc 100644 --- a/projects/ui/src/Components/UsagePlans/UsagePlanList/APIUsagePlansList.tsx +++ b/projects/ui/src/Components/UsagePlans/UsagePlanList/APIUsagePlansList.tsx @@ -2,7 +2,7 @@ import { useMemo } from "react"; import { di } from "react-magnetic-di"; import { API } from "../../../Apis/api-types"; import { useListApis } from "../../../Apis/shared_hooks"; -import { EmptyData } from "../../Common/EmptyData"; +import { SimpleEmptyContent } from "../../Common/EmptyData"; import { ErrorBoundary } from "../../Common/ErrorBoundary"; import { Loading } from "../../Common/Loading"; import { APIUsagePlanCard } from "./APIUsagePlanCard"; @@ -46,7 +46,7 @@ export function APIUsagePlansList() { )) ) : ( - + )} ); From 6e3a336d10623d88d52b4ebd2596737669fc49fe Mon Sep 17 00:00:00 2001 From: Nicholas Bucher Date: Wed, 11 Sep 2024 10:51:53 -0400 Subject: [PATCH 17/75] empty data rename Signed-off-by: Nicholas Bucher --- .../ApiProductDetailsPageBody.tsx | 13 ++++++------- .../SchemaTab/SchemaTabContent.tsx | 10 +++++----- projects/ui/src/Components/Apis/EmptyApisPage.tsx | 12 ++++-------- .../gloo-gateway-components/ApisTab/ApisList.tsx | 6 +++--- .../Apis/gloo-mesh-gateway-components/ApisList.tsx | 6 ++---- .../Details/ApiKeysSection/AppApiKeysSection.tsx | 4 ++-- .../AppApiSubscriptionsSection.tsx | 4 ++-- .../ui/src/Components/Apps/PageContent/AppsList.tsx | 8 +++----- projects/ui/src/Components/Common/EmptyData.tsx | 2 +- .../Common/SubscriptionsList/SubscriptionsList.tsx | 4 ++-- .../Teams/Details/AppsSection/TeamAppsSection.tsx | 4 ++-- .../Teams/Details/UsersSection/TeamUsersSection.tsx | 4 ++-- .../ui/src/Components/Teams/TeamsList/TeamsList.tsx | 4 ++-- .../UsagePlans/UsagePlanList/APIUsagePlansList.tsx | 4 ++-- .../Styles/global-styles/mantine-overrides.style.ts | 1 + 15 files changed, 39 insertions(+), 47 deletions(-) diff --git a/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageBody.tsx b/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageBody.tsx index bcaca627..0ea6fdd2 100644 --- a/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageBody.tsx +++ b/projects/ui/src/Components/ApiDetails/gloo-gateway-components/ApiProductDetailsPageBody.tsx @@ -7,7 +7,7 @@ import { ApiVersionSchema, } from "../../../Apis/api-types"; import { ContentWidthDiv } from "../../../Styles/ContentWidthHelpers"; -import { SimpleEmptyContent } from "../../Common/EmptyData"; +import { EmptyData } from "../../Common/EmptyData"; import DocsTabContent from "./DocsTab/DocsTabContent"; import SchemaTabContent from "./SchemaTab/SchemaTabContent"; @@ -80,17 +80,16 @@ export function ApiProductDetailsPageBody({ {includesDocumentation ? ( ) : ( - + You may add documentation for this API in the{" "} - + spec.versions[your-version].openapiMetadata.description {" "} - field of this{" "} - ApiProduct resource. - Markdown is supported. + field of this ApiProduct resource. Markdown is + supported. - + )}
diff --git a/projects/ui/src/Components/ApiDetails/gloo-gateway-components/SchemaTab/SchemaTabContent.tsx b/projects/ui/src/Components/ApiDetails/gloo-gateway-components/SchemaTab/SchemaTabContent.tsx index 7d5397de..198596a6 100644 --- a/projects/ui/src/Components/ApiDetails/gloo-gateway-components/SchemaTab/SchemaTabContent.tsx +++ b/projects/ui/src/Components/ApiDetails/gloo-gateway-components/SchemaTab/SchemaTabContent.tsx @@ -1,6 +1,6 @@ import { Box, Code } from "@mantine/core"; import { ApiVersion, ApiVersionSchema } from "../../../../Apis/api-types"; -import { SimpleEmptyContent } from "../../../Common/EmptyData"; +import { EmptyData } from "../../../Common/EmptyData"; import { ErrorBoundary } from "../../../Common/ErrorBoundary"; import { ApiSchemaDisplay } from "./ApiSchemaDisplay"; @@ -16,10 +16,10 @@ const SchemaTabContent = ({ if (!apiProductVersions.length) { return ( - + Add a version to the spec.versions field of this{" "} ApiProduct for data to appear. - + ); } @@ -31,13 +31,13 @@ const SchemaTabContent = ({ // There is a selected API version, but no schema. return ( - + The schema was not returned for this ApiProduct version.
Verify that your OpenApi spec was generated correctly in the corresponding ApiDoc resource for this{" "} Service. -
+
); } diff --git a/projects/ui/src/Components/Apis/EmptyApisPage.tsx b/projects/ui/src/Components/Apis/EmptyApisPage.tsx index 51dfd438..cd1dd706 100644 --- a/projects/ui/src/Components/Apis/EmptyApisPage.tsx +++ b/projects/ui/src/Components/Apis/EmptyApisPage.tsx @@ -5,7 +5,7 @@ import { AuthContext } from "../../Context/AuthContext"; import { apisImageURL } from "../../user_variables.tmplr"; import { BannerHeading } from "../Common/Banner/BannerHeading"; import { BannerHeadingTitle } from "../Common/Banner/BannerHeadingTitle"; -import { SimpleEmptyContent } from "../Common/EmptyData"; +import { EmptyData } from "../Common/EmptyData"; import { PageContainer } from "../Common/PageContainer"; import { StyledApisListMain } from "./gloo-mesh-gateway-components/ApisPage.style"; @@ -31,19 +31,15 @@ export const EmptyApisPageContent = () => { const { isLoggedIn } = useContext(AuthContext); if (!!isLoggedIn) - return ( - - No API Products have been created. - - ); + return No API Products have been created.; return ( - + To view API Products in private Portals, please log in.
To view API Products in public Portals, the Portal resource must have{" "} spec.visibility.public = true.
-
+ ); }; diff --git a/projects/ui/src/Components/Apis/gloo-gateway-components/ApisTab/ApisList.tsx b/projects/ui/src/Components/Apis/gloo-gateway-components/ApisTab/ApisList.tsx index 83a5ac36..51b8459f 100644 --- a/projects/ui/src/Components/Apis/gloo-gateway-components/ApisTab/ApisList.tsx +++ b/projects/ui/src/Components/Apis/gloo-gateway-components/ApisTab/ApisList.tsx @@ -12,7 +12,7 @@ import CustomPagination, { pageOptions, useCustomPagination, } from "../../../Common/CustomPagination"; -import { SimpleEmptyContent } from "../../../Common/EmptyData"; +import { EmptyData } from "../../../Common/EmptyData"; import { Loading } from "../../../Common/Loading"; import { ApisPageStyles } from "../../ApisPage.style"; import { ApiSummaryGridCard } from "./ApiSummaryCards/ApiSummaryGridCard"; @@ -79,11 +79,11 @@ export function ApisList({ return ; } if (!apiProductsList.length) { - return ; + return ; } if (!filteredApiProductsList.length) { return ( - + ); } if (preferGridView) { diff --git a/projects/ui/src/Components/Apis/gloo-mesh-gateway-components/ApisList.tsx b/projects/ui/src/Components/Apis/gloo-mesh-gateway-components/ApisList.tsx index 3a2a2921..bd193c01 100644 --- a/projects/ui/src/Components/Apis/gloo-mesh-gateway-components/ApisList.tsx +++ b/projects/ui/src/Components/Apis/gloo-mesh-gateway-components/ApisList.tsx @@ -7,7 +7,7 @@ import CustomPagination, { pageOptions, useCustomPagination, } from "../../Common/CustomPagination"; -import { SimpleEmptyContent } from "../../Common/EmptyData"; +import { EmptyData } from "../../Common/EmptyData"; import { Loading } from "../../Common/Loading"; import { ApiSummaryGridCard } from "./ApiSummaryGridCard"; import { ApiSummaryListCard } from "./ApiSummaryListCard"; @@ -72,9 +72,7 @@ export function ApisList({ } if (!displayedApisList.length) { - return ( - - ); + return ; } return ( <> diff --git a/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx b/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx index 2e145992..5a000b9d 100644 --- a/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx +++ b/projects/ui/src/Components/Apps/Details/ApiKeysSection/AppApiKeysSection.tsx @@ -16,7 +16,7 @@ import CustomPagination, { pageOptions, useCustomPagination, } from "../../../Common/CustomPagination"; -import { SimpleEmptyContent } from "../../../Common/EmptyData"; +import { EmptyData } from "../../../Common/EmptyData"; import { Loading } from "../../../Common/Loading"; import Table from "../../../Common/Table"; import ToggleAddButton from "../../../Common/ToggleAddButton"; @@ -87,7 +87,7 @@ const AppApiKeysSection = ({ app }: { app: App }) => { /> {!apiKeys?.length ? ( - + ) : ( diff --git a/projects/ui/src/Components/Apps/Details/ApiSubscriptionsSection/AppApiSubscriptionsSection.tsx b/projects/ui/src/Components/Apps/Details/ApiSubscriptionsSection/AppApiSubscriptionsSection.tsx index 4155066b..ee2caa1e 100644 --- a/projects/ui/src/Components/Apps/Details/ApiSubscriptionsSection/AppApiSubscriptionsSection.tsx +++ b/projects/ui/src/Components/Apps/Details/ApiSubscriptionsSection/AppApiSubscriptionsSection.tsx @@ -5,7 +5,7 @@ import { Icon } from "../../../../Assets/Icons"; import { DetailsPageStyles } from "../../../../Styles/shared/DetailsPageStyles"; import { UtilityStyles } from "../../../../Styles/shared/Utility.style"; import { Button } from "../../../Common/Button"; -import { SimpleEmptyContent } from "../../../Common/EmptyData"; +import { EmptyData } from "../../../Common/EmptyData"; import SubscriptionInfoCard from "../../../Common/SubscriptionsList/SubscriptionInfoCard/SubscriptionInfoCard"; import NewSubscriptionModal from "../Modals/NewSubscriptionModal"; @@ -44,7 +44,7 @@ const AppApiSubscriptionsSection = ({ {subscriptions.length === 0 && ( - + )} diff --git a/projects/ui/src/Components/Apps/PageContent/AppsList.tsx b/projects/ui/src/Components/Apps/PageContent/AppsList.tsx index c0b49191..18135daa 100644 --- a/projects/ui/src/Components/Apps/PageContent/AppsList.tsx +++ b/projects/ui/src/Components/Apps/PageContent/AppsList.tsx @@ -4,7 +4,7 @@ import { App, Team } from "../../../Apis/api-types"; import { useListAppsForTeams } from "../../../Apis/gg_hooks"; import { FilterPair, FilterType } from "../../../Utility/filter-utility"; import { omitErrorMessageResponse } from "../../../Utility/utility"; -import { SimpleEmptyContent } from "../../Common/EmptyData"; +import { EmptyData } from "../../Common/EmptyData"; import { Loading } from "../../Common/Loading"; import { AppsPageStyles } from "../AppsPage.style"; import { AppSummaryGridCard } from "./AppSummaryCards/AppSummaryGridCard"; @@ -86,12 +86,10 @@ export function AppsList({ return ; } if (!appsList?.length) { - return ; + return ; } if (!filteredAppsList.length) { - return ( - - ); + return ; } return ( diff --git a/projects/ui/src/Components/Common/EmptyData.tsx b/projects/ui/src/Components/Common/EmptyData.tsx index 54a2031e..bde84dbe 100644 --- a/projects/ui/src/Components/Common/EmptyData.tsx +++ b/projects/ui/src/Components/Common/EmptyData.tsx @@ -18,7 +18,7 @@ const StyledEmptyContentOuter = styled.div( ` ); -export const SimpleEmptyContent = (props: { +export const EmptyData = (props: { children?: React.ReactNode; title?: React.ReactNode; }) => { diff --git a/projects/ui/src/Components/Common/SubscriptionsList/SubscriptionsList.tsx b/projects/ui/src/Components/Common/SubscriptionsList/SubscriptionsList.tsx index 9479c885..b401c7eb 100644 --- a/projects/ui/src/Components/Common/SubscriptionsList/SubscriptionsList.tsx +++ b/projects/ui/src/Components/Common/SubscriptionsList/SubscriptionsList.tsx @@ -5,7 +5,7 @@ import { isSubscriptionsListError, } from "../../../Apis/api-types"; import { colors } from "../../../Styles"; -import { SimpleEmptyContent } from "../../Common/EmptyData"; +import { EmptyData } from "../../Common/EmptyData"; import { FiltrationProp } from "../Filters/AppliedFiltersSection"; import SubscriptionInfoCard from "./SubscriptionInfoCard/SubscriptionInfoCard"; @@ -35,7 +35,7 @@ const SubscriptionsList = ({ return null; } if (subscriptions.length === 0) { - return ; + return ; } return ( diff --git a/projects/ui/src/Components/Teams/Details/AppsSection/TeamAppsSection.tsx b/projects/ui/src/Components/Teams/Details/AppsSection/TeamAppsSection.tsx index 96a81dd0..e7407a2a 100644 --- a/projects/ui/src/Components/Teams/Details/AppsSection/TeamAppsSection.tsx +++ b/projects/ui/src/Components/Teams/Details/AppsSection/TeamAppsSection.tsx @@ -14,7 +14,7 @@ import CustomPagination, { pageOptions, useCustomPagination, } from "../../../Common/CustomPagination"; -import { SimpleEmptyContent } from "../../../Common/EmptyData"; +import { EmptyData } from "../../../Common/EmptyData"; import { Loading } from "../../../Common/Loading"; import Table from "../../../Common/Table"; import ToggleAddButton from "../../../Common/ToggleAddButton"; @@ -86,7 +86,7 @@ const TeamAppsSection = ({ team }: { team: Team }) => { )} {!apps?.length ? ( - + ) : ( diff --git a/projects/ui/src/Components/Teams/Details/UsersSection/TeamUsersSection.tsx b/projects/ui/src/Components/Teams/Details/UsersSection/TeamUsersSection.tsx index f0cc1060..fa1559a6 100644 --- a/projects/ui/src/Components/Teams/Details/UsersSection/TeamUsersSection.tsx +++ b/projects/ui/src/Components/Teams/Details/UsersSection/TeamUsersSection.tsx @@ -16,7 +16,7 @@ import CustomPagination, { pageOptions, useCustomPagination, } from "../../../Common/CustomPagination"; -import { SimpleEmptyContent } from "../../../Common/EmptyData"; +import { EmptyData } from "../../../Common/EmptyData"; import { Loading } from "../../../Common/Loading"; import Table from "../../../Common/Table"; import ToggleAddButton from "../../../Common/ToggleAddButton"; @@ -101,7 +101,7 @@ const TeamUsersSection = ({ team }: { team: Team }) => { {!members?.length ? ( {/* We never should get here, since the user must be a member. */} - + ) : ( diff --git a/projects/ui/src/Components/Teams/TeamsList/TeamsList.tsx b/projects/ui/src/Components/Teams/TeamsList/TeamsList.tsx index 5bedf4ce..0b711ce4 100644 --- a/projects/ui/src/Components/Teams/TeamsList/TeamsList.tsx +++ b/projects/ui/src/Components/Teams/TeamsList/TeamsList.tsx @@ -1,7 +1,7 @@ import { Box, Flex } from "@mantine/core"; import { di } from "react-magnetic-di"; import { useListTeams } from "../../../Apis/gg_hooks"; -import { SimpleEmptyContent } from "../../Common/EmptyData"; +import { EmptyData } from "../../Common/EmptyData"; import { Loading } from "../../Common/Loading"; import { TeamSummaryGridCard } from "./TeamSummaryCards/TeamSummaryGridCard"; @@ -16,7 +16,7 @@ export function TeamsList() { return ; } if (!teamsList?.length) { - return ; + return ; } return ( diff --git a/projects/ui/src/Components/UsagePlans/UsagePlanList/APIUsagePlansList.tsx b/projects/ui/src/Components/UsagePlans/UsagePlanList/APIUsagePlansList.tsx index bb93abbc..0808d446 100644 --- a/projects/ui/src/Components/UsagePlans/UsagePlanList/APIUsagePlansList.tsx +++ b/projects/ui/src/Components/UsagePlans/UsagePlanList/APIUsagePlansList.tsx @@ -2,7 +2,7 @@ import { useMemo } from "react"; import { di } from "react-magnetic-di"; import { API } from "../../../Apis/api-types"; import { useListApis } from "../../../Apis/shared_hooks"; -import { SimpleEmptyContent } from "../../Common/EmptyData"; +import { EmptyData } from "../../Common/EmptyData"; import { ErrorBoundary } from "../../Common/ErrorBoundary"; import { Loading } from "../../Common/Loading"; import { APIUsagePlanCard } from "./APIUsagePlanCard"; @@ -46,7 +46,7 @@ export function APIUsagePlansList() { )) ) : ( - + )} ); diff --git a/projects/ui/src/Styles/global-styles/mantine-overrides.style.ts b/projects/ui/src/Styles/global-styles/mantine-overrides.style.ts index 4eb8c2fc..bacc83a9 100644 --- a/projects/ui/src/Styles/global-styles/mantine-overrides.style.ts +++ b/projects/ui/src/Styles/global-styles/mantine-overrides.style.ts @@ -66,5 +66,6 @@ export const mantineGlobalStyles = css` code.mantine-Code-root { background-color: ${colors.januaryGreyDark1}; + white-space: nowrap; } `; From 7ca428ca0586f8cf38764f753b80ca0f43293358 Mon Sep 17 00:00:00 2001 From: Nicholas Bucher Date: Wed, 11 Sep 2024 12:49:21 -0400 Subject: [PATCH 18/75] generate api key modal complete. Signed-off-by: Nicholas Bucher --- projects/ui/src/Apis/gg_hooks.ts | 7 +- .../ApiKeysSection/AddApiKeysSubSection.tsx | 50 +++++---- .../Details/Modals/ViewCreatedApiKeyModal.tsx | 100 ++++++++++++++++++ 3 files changed, 135 insertions(+), 22 deletions(-) create mode 100644 projects/ui/src/Components/Apps/Details/Modals/ViewCreatedApiKeyModal.tsx diff --git a/projects/ui/src/Apis/gg_hooks.ts b/projects/ui/src/Apis/gg_hooks.ts index 1e5fe745..5b6b3143 100644 --- a/projects/ui/src/Apis/gg_hooks.ts +++ b/projects/ui/src/Apis/gg_hooks.ts @@ -453,13 +453,16 @@ type CreateApiKeyParams = MutationWithArgs<{ apiKeyName: string }>; export function useCreateApiKeyMutation(appId: string) { const { latestAccessToken } = useContext(AuthContext); const createApiKey = async (_: string, { arg }: CreateApiKeyParams) => { - await fetchJSON(`/apps/${appId}/api-keys`, { + return await fetchJSON(`/apps/${appId}/api-keys`, { method: "POST", headers: getLatestAuthHeaders(latestAccessToken), body: JSON.stringify(arg), }); }; - return useSWRMutation(`/apps/${appId}/api-keys`, createApiKey); + return useSWRMutation( + `/apps/${appId}/api-keys`, + createApiKey + ); } // -------------------------------- // diff --git a/projects/ui/src/Components/Apps/Details/ApiKeysSection/AddApiKeysSubSection.tsx b/projects/ui/src/Components/Apps/Details/ApiKeysSection/AddApiKeysSubSection.tsx index acba192e..fffb9533 100644 --- a/projects/ui/src/Components/Apps/Details/ApiKeysSection/AddApiKeysSubSection.tsx +++ b/projects/ui/src/Components/Apps/Details/ApiKeysSection/AddApiKeysSubSection.tsx @@ -7,6 +7,7 @@ import { useCreateApiKeyMutation } from "../../../../Apis/gg_hooks"; import { DetailsPageStyles } from "../../../../Styles/shared/DetailsPageStyles"; import { Accordion } from "../../../Common/Accordion"; import { Button } from "../../../Common/Button"; +import ViewCreatedApiKeyModal from "../Modals/ViewCreatedApiKeyModal"; const AddApiKeysSubSection = ({ open, @@ -37,6 +38,7 @@ const AddApiKeysSubSection = ({ // // Form Submit // + const [createdApiKey, setCreatedApiKey] = useState(""); const { trigger: createApiKey } = useCreateApiKeyMutation(app.id); const onSubmit = async (e?: FormEvent) => { e?.preventDefault(); @@ -44,37 +46,45 @@ const AddApiKeysSubSection = ({ if (!isValid || isFormDisabled) { return; } - await toast.promise(createApiKey({ apiKeyName: formAppName }), { + const res = await toast.promise(createApiKey({ apiKeyName: formAppName }), { error: "There was an error creating the API Key.", loading: "Creating the API Key...", success: "Created the API Key!", }); onClose(); + setCreatedApiKey(res.apiKey); }; // // Render // return ( - - - - setFormAppName(e.target.value)} - /> - - - - + <> + + + + setFormAppName(e.target.value)} + /> + + + + + setCreatedApiKey("")} + /> + ); }; diff --git a/projects/ui/src/Components/Apps/Details/Modals/ViewCreatedApiKeyModal.tsx b/projects/ui/src/Components/Apps/Details/Modals/ViewCreatedApiKeyModal.tsx new file mode 100644 index 00000000..7cedc78a --- /dev/null +++ b/projects/ui/src/Components/Apps/Details/Modals/ViewCreatedApiKeyModal.tsx @@ -0,0 +1,100 @@ +import { Alert, Box, CloseButton, Flex } from "@mantine/core"; +import { useEffect, useState } from "react"; +import toast from "react-hot-toast"; +import { Icon } from "../../../../Assets/Icons"; +import { FormModalStyles } from "../../../../Styles/shared/FormModalStyles"; +import { copyToClipboard } from "../../../../Utility/utility"; +import { Button } from "../../../Common/Button"; + +const ViewCreatedApiKeyModal = ({ + apiKey, + open, + onCloseModal, +}: { + apiKey: string; + open: boolean; + onCloseModal: () => void; +}) => { + const [hasCopiedKey, setHasCopiedKey] = useState(false); + + useEffect(() => { + // Reset state on close. + if (!open) { + setHasCopiedKey(false); + } + }, [open]); + + const handleOnClose = () => { + if (!hasCopiedKey) { + return; + } + onCloseModal(); + }; + + // + // Render + // + return ( + + + + Created API Key + + {hasCopiedKey && ( + + )} + + + + } + title="Warning!" + color="orange" + > + This API Key value will not be available later. Please click the API + Key value to copy and secure this value now. + + + + + + + + + + ); +}; + +export default ViewCreatedApiKeyModal; From 4485944fc3aa0f26899612fe90e2a6952583476e Mon Sep 17 00:00:00 2001 From: Nicholas Bucher Date: Thu, 12 Sep 2024 13:05:53 -0400 Subject: [PATCH 19/75] changelog Signed-off-by: Nicholas Bucher --- changelog/v0.0.36/custom-pages.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelog/v0.0.36/custom-pages.yaml diff --git a/changelog/v0.0.36/custom-pages.yaml b/changelog/v0.0.36/custom-pages.yaml new file mode 100644 index 00000000..504cc325 --- /dev/null +++ b/changelog/v0.0.36/custom-pages.yaml @@ -0,0 +1,5 @@ +changelog: + - type: FIX + issueLink: https://github.com/solo-io/solo-projects/issues/6860 + description: >- + Adds the ability for users to create custom pages that show up in the UI. From d61236142173ea34bf794eafe0f116bfa4da0da0 Mon Sep 17 00:00:00 2001 From: Nicholas Bucher Date: Fri, 13 Sep 2024 15:59:38 -0400 Subject: [PATCH 20/75] added more custom pages styles, and updated readme Signed-off-by: Nicholas Bucher --- Dockerfile | 4 +- Makefile | 7 + README.md | 4 +- projects/ui/package.json | 1 + projects/ui/public/pages/another-page.html | 44 ++++++ projects/ui/public/pages/custom-page.md | 37 +++++ projects/ui/public/pages/gg-logo.png | Bin 0 -> 2536 bytes .../DocsTab/DocsTabContent.tsx | 26 +--- projects/ui/src/Components/App.tsx | 23 ++-- .../ui/src/Components/AppContentRoutes.tsx | 19 +++ .../Components/Common/MarkdownRenderer.tsx | 74 ++++++++++ .../CustomPage/Content/CustomHtmlPage.tsx | 21 +++ .../CustomPage/Content/CustomMarkdownPage.tsx | 31 +++++ .../CustomPage/CustomPageLanding.tsx | 109 +++++++++++++++ .../Structure/BasicAuthVariant/Header.tsx | 12 +- .../ui/src/Components/Structure/Footer.tsx | 4 +- .../src/Components/Structure/Header.style.tsx | 7 +- projects/ui/src/Context/AppUtilsContext.tsx | 38 ++++++ .../Styles/global-styles/highlight.js.min.css | 126 ++++++++++++++++++ projects/ui/src/Styles/global-styles/index.ts | 2 + .../ui/src/Styles/global-styles/site.style.ts | 2 +- .../src/Styles/global-styles/style-reset.css | 2 +- projects/ui/src/Utility/utility.ts | 32 ++++- projects/ui/src/user_variables.tmplr.ts | 22 +++ projects/ui/yarn.lock | 5 + readme_assets/custom-pages-navbar.png | Bin 0 -> 21290 bytes 26 files changed, 609 insertions(+), 43 deletions(-) create mode 100644 projects/ui/public/pages/another-page.html create mode 100644 projects/ui/public/pages/custom-page.md create mode 100644 projects/ui/public/pages/gg-logo.png create mode 100644 projects/ui/src/Components/Common/MarkdownRenderer.tsx create mode 100644 projects/ui/src/Components/CustomPage/Content/CustomHtmlPage.tsx create mode 100644 projects/ui/src/Components/CustomPage/Content/CustomMarkdownPage.tsx create mode 100644 projects/ui/src/Components/CustomPage/CustomPageLanding.tsx create mode 100644 projects/ui/src/Context/AppUtilsContext.tsx create mode 100644 projects/ui/src/Styles/global-styles/highlight.js.min.css create mode 100644 readme_assets/custom-pages-navbar.png diff --git a/Dockerfile b/Dockerfile index 3b3f43cc..7dc8da41 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,7 +45,8 @@ ENV VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \ VITE_HOME_IMAGE_URL=$VITE_HOME_IMAGE_URL \ VITE_APIS_IMAGE_URL=$VITE_APIS_IMAGE_URL \ VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \ - VITE_COMPANY_NAME=$VITE_COMPANY_NAME + VITE_COMPANY_NAME=$VITE_COMPANY_NAME \ + VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES # Copy the server files, (this includes the UI build). WORKDIR /app @@ -70,4 +71,5 @@ ENTRYPOINT VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \ VITE_APIS_IMAGE_URL=$VITE_APIS_IMAGE_URL \ VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \ VITE_COMPANY_NAME=$VITE_COMPANY_NAME \ + VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES \ node ./bin/www diff --git a/Makefile b/Makefile index ccfdb8fc..eae3def5 100644 --- a/Makefile +++ b/Makefile @@ -104,6 +104,13 @@ ifneq ($(VITE_COMPANY_NAME),) else ifneq ($(COMPANY_NAME),) UI_ARGS += VITE_COMPANY_NAME=$(COMPANY_NAME) endif +# +# CUSTOM PAGES +ifneq ($(VITE_CUSTOM PAGES),) + UI_ARGS += VITE_CUSTOM PAGES=$(VITE_CUSTOM_PAGES) +else ifneq ($(CUSTOM_PAGES),) + UI_ARGS += VITE_CUSTOM_PAGES=$(CUSTOM_PAGES) +endif diff --git a/README.md b/README.md index fa8203bb..d39ff7e3 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ This is an example Solo.io Gloo Platform Dev Portal frontend app, built with [Vi 2. Build your image. ```sh - docker build -t "your-image-name" + docker build -t "your-image-name" . ``` 3. Push your image: @@ -137,6 +137,8 @@ You can add these environment variables to a `.env.local` file in the `projects/ - `VITE_HOME_IMAGE_URL` - This is an optional parameter to set the image URL on the home page. - `VITE_APIS_IMAGE_URL` - This is an optional parameter to set the image URL on the apis page. - `VITE_LOGO_IMAGE_URL` - This is an optional parameter to set the image URL for the logo in the upper left. +- `VITE_CUSTOM_PAGES` - This is an optional value that describes Markdown or HTML custom pages that have been added to the `projects/ui/src/public` folder. In order to test this feature out out with the provided examples, set your `VITE_CUSTOM_PAGES` value to: `'[{"title": "Custom Page", "path": "/pages/custom-page.md"}, {"title": "Another Page", "path": "/pages/another-page.html"}]'`. When the website is opened, there should be two new pages in the top navigation bar (one for the `"Custom Page"` using Markdown, and one for `"Another Page"`, using HTML). + ![custom pages example](readme_assets/custom-pages-navbar.png) #### Environment Variables for PKCE Authorization Flow diff --git a/projects/ui/package.json b/projects/ui/package.json index 17e5eeb8..dbed14df 100644 --- a/projects/ui/package.json +++ b/projects/ui/package.json @@ -25,6 +25,7 @@ "@mantine/hooks": "^6.0.6", "@types/color": "^3.0.6", "color": "^4.2.3", + "highlight.js": "^11.10.0", "mobx": "^6.8.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/projects/ui/public/pages/another-page.html b/projects/ui/public/pages/another-page.html new file mode 100644 index 00000000..548dce60 --- /dev/null +++ b/projects/ui/public/pages/another-page.html @@ -0,0 +1,44 @@ + + + + + +

Custom HTML Page

+ +

Section 1

+ +
    +
  • This is an example custom page.
  • +
  • Feel free to update this to your needs.
  • +
+ +

Section 2

+ +

Any HTML content can go here.

+ + Here is an image: +
+ Gloo Gateway Logo + +
+ + + diff --git a/projects/ui/public/pages/custom-page.md b/projects/ui/public/pages/custom-page.md new file mode 100644 index 00000000..dfb8f633 --- /dev/null +++ b/projects/ui/public/pages/custom-page.md @@ -0,0 +1,37 @@ +# Markdown Page Test (h1) + +This is a custom Markdown page test. + +## Section 1 (h2) + +- Supports bullet points +- Supports bullet points + +### 1.1 (h3) + +Testing that **Bold works** here. + +#### 1.1.1 (h4) + +Testing that _Italics works_ here. + +##### 1.1.1 (h5) + +Links work: [www.solo.io](www.solo.io) + +1. Numbered lists work +2. test +3. test + +Images work: + +![Gloo Gateway Logo](/pages/gg-logo.png) + +And code does too: + +```ts +const x = 123; +function y() { + return x + 5; +} +``` diff --git a/projects/ui/public/pages/gg-logo.png b/projects/ui/public/pages/gg-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..053935de9010d88b230d5a5c7f2ae2212e9f9476 GIT binary patch literal 2536 zcmbVOc{J1u8~)80V~KHXCD{oXlzqL~h7e*JGuDi)>?X2IQe)gfV~UEgOqRGvcG;3; zWN)aHWM9g@4G~w!r}Le2|NhSR$MZhVyPfx(_mB6y_ib%1adQfD0sz2mVU9o^bL26o z?9gK?s9+^=OrTKYC1arcoygL$gYb5+xNdC?C>(2c02J>FKz^4TL--f~z>*6BSdJO= zJC+OnHyfGD@~@`;F3f={+5!Lv(gIysyQB#ots~zz8u7N<4Pu%irvtntli7^Ymx}s`dW7ie5vS zFjxE5QC})B6BRtp6Mz2r*32w&3$w?(S7bqq8Gqjk6=|Ge@k|QvIT_FRu{|jhTR(bc zUg;(@u5*`G8+s)o@hf2O|pH66ybDPGsWa>CCyE1tdXTYcq0;i_l)oiI(a%ErGcfgp& zp~TsdzZZNhBAQGqwHi(*KW+bP))+`^n^X^NM7_QS#1l&7siM`PbjcY$FMNGSgFB&Q z9PTfp$3o!<%8=AMZ8~LDcnx<^5ILxh?3y-&ztU)brl0S>ay*VKxgyv#oF2Dx?IpGN zb)9fqnb&eBtdgnNe#p{zphm+G$X>KCk1~cZ_Vgg{?NGB%WDB)j!StHw-|iNQ?;Tt2gL|y^Fo`@u1WiDG!ho-QM{S#;OA0}6tA|V zfcA+cx1^6ZGk}z)xBPcA9^cfprfqSlmm!Yls_tg`C)XxFod~|CP_vW$I(z9y&0h9e zOq!6yI`2v^hOEBv@gbI@{zQP870GV}^kLtMC#WunJX>8P%G~Iag=qhi9B+$|K(Tj}m0>!8`du61dG;AjLp{j zQ0vZfQ8E?e>AbeoQ}GP*UndI1G@1d|G^QzzcjkI$C~xoA{^TjmqB~5q&t!ic$@iWP zF&I@O_w0?b<2rT0e{FPq^>&bXw>aXvFHJKc4VvAUL!TSN-TdYzQ#n#;=9+q@ckmf3 zwnF_aB{^&_d;frcW3-=FHHsl6kyF!Z*cPsI_K3_%KApnMwQr=jp2XyJenD%$=viyM z?SiNlN?CU@|AjAVRpRO{fjZ7ZXDH)$TU`*UEbHrIj}Ku!BF+$zAcenYg3qtSn%Di5 za;peI=uv@gR?LzcwC5zy%~7wI%nj=1uIEaA0LZPq-Ex?J#fhFog?|AK7)^6kR5frD z_hbXiFV} zh$v~D3pZ;$7kpNp*lZzMCx+gjl$ zLpwz67~aTf^bxI<>bp#k{;SYa6*OcAf71lfHulk#<;VVi3ICc*nJHt+hXrIt0A$!J zs~V-ic8l7$Ncg(%lL_qG>R``6v~&Ntm?=xYh=L76K`{B2q(Y8Lo>Z1PcXjI!?+AFt zFWUp2q9^#}^Iv($nRgQTy&;K5*srr`K3gsqs?v-&w8QOGMy?Q425{IDpl}I=LIsWs zvcj+cNjePCi8>4FLbS&yL55?Vr@xS)r~7DEk^sFw1h1w-g!sAH>i)p8<$1h#40z_v z&`*L_4N+G1c`nN8yzDDHsOm%y0I+ANI-?Peuic9m$(wVVl;nGYY=p@{$3u@@(atvoA)~<(L zZ9p2Q5CWT@2ugc>R!VfXp4bp}Q+~)-$=!_-RWYjjtOTF(Ci7J;<{dGFeH+DDyl4|4 z=<_Lrl_k#{V8P%zx5h*_*GPE1Vl5xf9jd}paWjtewhj*sQG*_xqfUW11%t{$@D_QfVc#0}9 z^;uGTmEN~=2J+=SIfFW9&c&IB4=6EuNXiCz)0SnnEL3O^Y2G!vaGwkrv9DJQYPxiM zO(}!cfs3HaCJ}FFyNTctRu>htFAou3YZA>vgxIF=>2k|U_rce;qR&>Nf}lvEN5DWP0m85O)m4#zs2?mapE7jWQkoR@!vf5O9iZQ`u?GTsnGU z(R;TviPXe)Lo{Vy@IEb{_tT);}Rm*UaHze#M z1Xg-?B-rBMuF~{q!rU{#9` css` - padding: 30px; - * { - margin: revert; - padding: revert; - font-family: revert; - font-weight: revert; - } - blockquote p { - color: ${theme.augustGrey}; - } - ` -); +import MarkdownRenderer from "../../../Common/MarkdownRenderer"; const DocsTabContent = ({ selectedApiVersion, @@ -29,11 +11,7 @@ const DocsTabContent = ({ return ( - - - {selectedApiVersion.documentation} - - + ); diff --git a/projects/ui/src/Components/App.tsx b/projects/ui/src/Components/App.tsx index 9dc89cb4..c0315548 100644 --- a/projects/ui/src/Components/App.tsx +++ b/projects/ui/src/Components/App.tsx @@ -1,6 +1,7 @@ import { Global, ThemeProvider } from "@emotion/react"; import { MantineProvider } from "@mantine/core"; import { AppContextProvider } from "../Context/AppContext"; +import { AppUtilsContextProvider } from "../Context/AppUtilsContext"; import { defaultTheme, globalStyles } from "../Styles"; import { mantineThemeOverride } from "../Styles/global-styles/mantine-theme"; import PortalServerTypeChecker from "../Utility/PortalServerTypeChecker"; @@ -15,17 +16,19 @@ export function App() { return ( - - + + + - - - - + + + + + ); } diff --git a/projects/ui/src/Components/AppContentRoutes.tsx b/projects/ui/src/Components/AppContentRoutes.tsx index aaec904c..e7d89cfb 100644 --- a/projects/ui/src/Components/AppContentRoutes.tsx +++ b/projects/ui/src/Components/AppContentRoutes.tsx @@ -4,9 +4,11 @@ import { Navigate, Route, Routes } from "react-router-dom"; import { AppContext } from "../Context/AppContext"; import { AuthContext } from "../Context/AuthContext"; import { + customPages, oidcAuthCodeConfigCallbackPath, oidcAuthCodeConfigLogoutPath, } from "../user_variables.tmplr"; +import { getCustomPagePath } from "../Utility/utility"; import AdminSubscriptionsPage from "./AdminSubscriptions/AdminSubscriptionsPage"; import AdminTeamsPage from "./AdminTeams/AdminTeamsPage"; import { ApiDetailsPage } from "./ApiDetails/ApiDetailsPage"; @@ -15,6 +17,7 @@ import { AppsPage } from "./Apps/AppsPage"; import AppDetailsPage from "./Apps/Details/AppDetailsPage"; import { ErrorBoundary } from "./Common/ErrorBoundary"; import LoggedOut from "./Common/LoggedOut"; +import CustomPageLanding from "./CustomPage/CustomPageLanding"; import { HomePage } from "./Home/HomePage"; import { Footer } from "./Structure/Footer"; import TeamDetailsPage from "./Teams/Details/TeamDetailsPage"; @@ -173,6 +176,22 @@ function AppContentRoutes() { )} )} + {customPages.map((page) => ( + <> + {getCustomPagePath(page)} + + + + } + /> + + ))}