Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added oauth section to app details page. #104

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ ENV VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \
VITE_SWAGGER_CONFIG_URL=$VITE_SWAGGER_CONFIG_URL \
VITE_AUDIENCE=$VITE_AUDIENCE \
VITE_HOME_IMAGE_URL=$VITE_HOME_IMAGE_URL \
VITE_APIS_IMAGE_URL=$VITE_APIS_IMAGE_URL \
VITE_BANNER_IMAGE_URL=$VITE_BANNER_IMAGE_URL \
VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \
VITE_COMPANY_NAME=$VITE_COMPANY_NAME \
VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES \
Expand Down Expand Up @@ -71,7 +71,7 @@ ENTRYPOINT VITE_PORTAL_SERVER_URL=$VITE_PORTAL_SERVER_URL \
VITE_SWAGGER_CONFIG_URL=$VITE_SWAGGER_CONFIG_URL \
VITE_AUDIENCE=$VITE_AUDIENCE \
VITE_HOME_IMAGE_URL=$VITE_HOME_IMAGE_URL \
VITE_APIS_IMAGE_URL=$VITE_APIS_IMAGE_URL \
VITE_BANNER_IMAGE_URL=$VITE_BANNER_IMAGE_URL \
VITE_LOGO_IMAGE_URL=$VITE_LOGO_IMAGE_URL \
VITE_COMPANY_NAME=$VITE_COMPANY_NAME \
VITE_CUSTOM_PAGES=$VITE_CUSTOM_PAGES \
Expand Down
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ else ifneq ($(HOME_IMAGE_URL),)
UI_ARGS += VITE_HOME_IMAGE_URL=$(HOME_IMAGE_URL)
endif
#
# APIS_IMAGE_URL
ifneq ($(VITE_APIS_IMAGE_URL),)
UI_ARGS += VITE_APIS_IMAGE_URL=$(VITE_APIS_IMAGE_URL)
else ifneq ($(APIS_IMAGE_URL),)
UI_ARGS += VITE_APIS_IMAGE_URL=$(APIS_IMAGE_URL)
# BANNER_IMAGE_URL
ifneq ($(VITE_BANNER_IMAGE_URL),)
UI_ARGS += VITE_BANNER_IMAGE_URL=$(VITE_BANNER_IMAGE_URL)
else ifneq ($(BANNER_IMAGE_URL),)
UI_ARGS += VITE_BANNER_IMAGE_URL=$(BANNER_IMAGE_URL)
endif
#
# LOGO_IMAGE_URL
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ You can add these environment variables to a `.env.local` file in the `projects/
4. rebuilding the project.
- `VITE_AUDIENCE` - This is an optional parameter if using Auth0 and need to send an audience parameter in your authorization requests. This should not be URL encoded, since it will be URL encoded when the request is sent.
- `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_BANNER_IMAGE_URL` - This is an optional parameter to set the banner image URL for the teams, apps, subscriptions, and API's pages.
- `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:
```
Expand Down
9 changes: 9 additions & 0 deletions changelog/v0.0.36/app-oauth-client-functionality.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
changelog:
- type: NEW_FEATURE
issueLink: https://github.com/solo-io/solo-projects/issues/6886
description: >-
Adds the ability to create and delete oauth clients from the App details page.
- type: NEW_FEATURE
issueLink: https://github.com/solo-io/solo-projects/issues/6953
description: >-
Adds the ability to customize all banner images through the VITE_BANNER_IMAGE_URL environment variable.
11 changes: 9 additions & 2 deletions projects/ui/src/Apis/api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,13 @@ export type ApiVersionExtended = ApiVersion & {
apiProductName: string;
};

export type OauthCredential = {
id: string;
idpClientId: string;
idpClientSecret: string;
idpClientName: string;
};

//
// Shared Types
//
Expand All @@ -170,8 +177,8 @@ export type User = {
name: string;
email: string;
username: string;
// TODO: Once auth is working, check if we can get admin info here and update the areas that use admin endpoints (e.g. subscriptions areas).
// admin: string;
// isAdmin may be undefined on older versions of the gg portal server.
isAdmin?: string;
};

/**
Expand Down
44 changes: 35 additions & 9 deletions projects/ui/src/Apis/gg_hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
ApiVersion,
App,
Member,
OauthCredential,
Subscription,
SubscriptionStatus,
SubscriptionsListError,
Expand All @@ -28,7 +29,7 @@ export function useGetCurrentUser() {
return useSwrWithAuth<User>("/me");
}

// region Apps + API Keys
// region Apps + API Keys + OAuth
export function useListAppsForTeam(team: Team) {
return useSwrWithAuth<App[]>(`/teams/${team.id}/apps`);
}
Expand Down Expand Up @@ -59,9 +60,11 @@ export function useGetAppDetails(id?: string) {
export function useListApiKeysForApp(appId: string) {
return useSwrWithAuth<ApiKey[]>(`/apps/${appId}/api-keys`);
}
export function useGetOauthCredentialsForApp(appId: string) {
return useSwrWithAuth<OauthCredential>(`/apps/${appId}/oauth-credentials`);
}

// region Teams
const TEAMS_SWR_KEY = "teams";
export function useListTeams() {
return useSwrWithAuth<Team[]>(`/teams`);
}
Expand Down Expand Up @@ -139,14 +142,12 @@ type CreateTeamParams = MutationWithArgs<{ name: string; description: string }>;

export function useCreateTeamMutation() {
const { latestAccessToken } = useContext(AuthContext);
const { mutate } = useSWRConfig();
const createTeam = async (url: string, { arg }: CreateTeamParams) => {
const res = await fetchJSON(url, {
method: "POST",
headers: getLatestAuthHeaders(latestAccessToken),
body: JSON.stringify(arg),
});
mutate(TEAMS_SWR_KEY);
return res as Team;
};
return useSWRMutation(`/teams`, createTeam);
Expand Down Expand Up @@ -269,7 +270,6 @@ export function useUpdateTeamMutation() {
headers: getLatestAuthHeaders(latestAccessToken),
body: JSON.stringify({ name: teamName, description: teamDescription }),
});
mutate(TEAMS_SWR_KEY);
mutate(`/teams/${teamId}`);
};
return useSWRMutation("update-team", updateTeam);
Expand Down Expand Up @@ -416,13 +416,11 @@ type DeleteTeamParams = MutationWithArgs<{ teamId: string }>;

export function useDeleteTeamMutation() {
const { latestAccessToken } = useContext(AuthContext);
const { mutate } = useSWRConfig();
const deleteTeam = async (_: string, { arg }: DeleteTeamParams) => {
await fetchJSON(`/teams/${arg.teamId}`, {
method: "DELETE",
headers: getLatestAuthHeaders(latestAccessToken),
});
mutate(TEAMS_SWR_KEY);
};
return useSWRMutation(`delete-team`, deleteTeam);
}
Expand All @@ -434,13 +432,11 @@ type DeleteAppParams = MutationWithArgs<{ appId: string }>;

export function useDeleteAppMutation() {
const { latestAccessToken } = useContext(AuthContext);
const { mutate } = useSWRConfig();
const deleteApp = async (_: string, { arg }: DeleteAppParams) => {
await fetchJSON(`/apps/${arg.appId}`, {
method: "DELETE",
headers: getLatestAuthHeaders(latestAccessToken),
});
mutate(TEAMS_SWR_KEY);
};
return useSWRMutation(`delete-team`, deleteApp);
}
Expand Down Expand Up @@ -480,3 +476,33 @@ export function useDeleteApiKeyMutation(appId: string) {
};
return useSWRMutation(`/apps/${appId}/api-keys`, deleteApiKey);
}

// -------------------------------- //
// region Create OAuth Client

export function useCreateOAuthMutation(appId: string) {
const { latestAccessToken } = useContext(AuthContext);
const createOAuth = async () => {
return (await fetchJSON(`/apps/${appId}/oauth-credentials`, {
method: "POST",
headers: getLatestAuthHeaders(latestAccessToken),
})) as OauthCredential;
};
return useSWRMutation(`/apps/${appId}/oauth-credentials`, createOAuth);
}

// -------------------------------- //
// region Delete OAuth Client

type DeleteOAuthParams = MutationWithArgs<{ credentialId: string }>;

export function useDeleteOAuthMutation(appId: string) {
const { latestAccessToken } = useContext(AuthContext);
const deleteOAuth = async (_: string, { arg }: DeleteOAuthParams) => {
await fetchJSON(`/oauth-credentials/${arg.credentialId}`, {
method: "DELETE",
headers: getLatestAuthHeaders(latestAccessToken),
});
};
return useSWRMutation(`/apps/${appId}/oauth-credentials`, deleteOAuth);
}
2 changes: 0 additions & 2 deletions projects/ui/src/Components/Apis/EmptyApisPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Code } from "@mantine/core";
import { Icon } from "../../Assets/Icons";
import { useIsLoggedIn } from "../../Context/AuthContext";
import { apisImageURL } from "../../user_variables.tmplr";
import { BannerHeading } from "../Common/Banner/BannerHeading";
import { BannerHeadingTitle } from "../Common/Banner/BannerHeadingTitle";
import { EmptyData } from "../Common/EmptyData";
Expand All @@ -12,7 +11,6 @@ export function EmptyApisPage() {
return (
<PageContainer>
<BannerHeading
bgImageURL={apisImageURL}
title={<BannerHeadingTitle text={"APIs"} logo={<Icon.CodeGear />} />}
description={
"Browse the list of APIs and documentation in this portal. From here you can get the information you need to make API calls."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
} from "../../../Apis/gg_hooks";
import { Icon } from "../../../Assets/Icons";
import { colors } from "../../../Styles";
import { apisImageURL } from "../../../user_variables.tmplr";
import { BannerHeading } from "../../Common/Banner/BannerHeading";
import { BannerHeadingTitle } from "../../Common/Banner/BannerHeadingTitle";
import { Loading } from "../../Common/Loading";
Expand All @@ -36,7 +35,6 @@ export function GG_ApisPage() {
return (
<PageContainer>
<BannerHeading
bgImageURL={apisImageURL}
title={<BannerHeadingTitle text={"APIs"} logo={<Icon.CodeGear />} />}
description={
"Browse the list of APIs and documentation in this portal. From here you can get the information you need to make API calls."
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useState } from "react";
import { Icon } from "../../../Assets/Icons";
import { apisImageURL } from "../../../user_variables.tmplr";
import { BannerHeading } from "../../Common/Banner/BannerHeading";
import { BannerHeadingTitle } from "../../Common/Banner/BannerHeadingTitle";
import { ErrorBoundary } from "../../Common/ErrorBoundary";
Expand Down Expand Up @@ -30,7 +29,6 @@ export function GMG_ApisPage() {
return (
<PageContainer>
<BannerHeading
bgImageURL={apisImageURL}
title={<BannerHeadingTitle text={"APIs"} logo={<Icon.CodeGear />} />}
description={
"Browse the list of APIs and documentation in this portal. From here you can get the information you need to make API calls."
Expand Down
25 changes: 11 additions & 14 deletions projects/ui/src/Components/AppContentRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,20 +177,17 @@ function AppContentRoutes() {
</>
)}
{customPages.map((page) => (
<>
{getCustomPagePath(page)}
<Route
key={page.path}
path={getCustomPagePath(page)}
element={
<ErrorBoundary
fallback={`There was an issue displaying the custom ${page.title} page.`}
>
<CustomPageLanding />
</ErrorBoundary>
}
/>
</>
<Route
key={page.path}
path={getCustomPagePath(page)}
element={
<ErrorBoundary
fallback={`There was an issue displaying the custom ${page.title} page.`}
>
<CustomPageLanding />
</ErrorBoundary>
}
/>
))}
</Routes>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +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";
import ViewCreatedItemModal from "../Modals/ViewCreatedItemModal";

const AddApiKeysSubSection = ({
open,
Expand Down Expand Up @@ -79,8 +79,10 @@ const AddApiKeysSubSection = ({
</DetailsPageStyles.AddItemForm>
</Box>
</Accordion>
<ViewCreatedApiKeyModal
apiKey={createdApiKey}
<ViewCreatedItemModal
createdObjectName="API Key"
itemToCopyName="API Key"
itemToCopyValue={createdApiKey}
open={!!createdApiKey}
onCloseModal={() => setCreatedApiKey("")}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { Box, Flex } from "@mantine/core";
import { useContext, useMemo, useState } from "react";
import { 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 { useListApiKeysForApp } from "../../../../Apis/gg_hooks";
import { useIsAdmin } from "../../../../Context/AuthContext";
import { DetailsPageStyles } from "../../../../Styles/shared/DetailsPageStyles";
import { GridCardStyles } from "../../../../Styles/shared/GridCard.style";
import { UtilityStyles } from "../../../../Styles/shared/Utility.style";
Expand All @@ -24,9 +21,9 @@ 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);
di(useIsAdmin, useListApiKeysForApp);
const isAdmin = useIsAdmin();
const { data: apiKeys } = useListApiKeysForApp(app.id);
const [showAddApiKeySubSection, setShowAddApiKeySubSection] = useState(false);

const customPaginationData = useCustomPagination(
Expand Down Expand Up @@ -63,7 +60,7 @@ const AppApiKeysSection = ({ app }: { app: App }) => {
});
}, [paginatedData]);

if (isLoading) {
if (apiKeys === undefined) {
return <Loading />;
}
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,6 @@ export const AppDetailsPageContent = ({ app }: { app: App }) => {
[teams, app]
);

// Mock data for testing
// app.idpClientId = "4df81266-f855-466d-8ded-699056780850";
// app.idpClientName = "test-idp";
// app.idpClientSecret = "hidden";
const appHasOAuthClient =
app.idpClientId && app.idpClientName && app.idpClientSecret;

return (
<PageContainer>
<BannerHeading
Expand Down Expand Up @@ -83,7 +76,7 @@ export const AppDetailsPageContent = ({ app }: { app: App }) => {
/>
<Box px={"30px"}>
<Flex gap={"30px"} direction={"column"}>
{appHasOAuthClient && <AppAuthenticationSection app={app} />}
<AppAuthenticationSection app={app} />

<AppApiKeysSection app={app} />

Expand Down
Loading
Loading