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

Adding Custom Pages #100

Merged
merged 10 commits into from
Sep 16, 2024
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: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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



Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -137,6 +137,13 @@ 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": "Markdown Example", "path": "/pages/markdown-example.md"}, {"title": "HTML Example", "path": "/pages/html-example.html"}]'
```
When the website is opened, there should be two new pages in the top navigation bar.
![custom pages example](readme_assets/custom-pages-navbar.png)
The custom page's `path` property must be publicly accessible and end with `.md` or `.html`.

#### Environment Variables for PKCE Authorization Flow

Expand Down
5 changes: 5 additions & 0 deletions changelog/v0.0.36/custom-pages.yaml
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions projects/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Binary file added projects/ui/public/pages/gg-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions projects/ui/public/pages/html-example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!doctype html>
<html>
<body>
<style>
body {
padding: 20px 50px;
/* background-color: bisque; */
}
</style>

<h1>Example HTML Page</h1>

<h2>Section 1</h2>

<ul>
<li>This is an example custom page.</li>
<li>Feel free to update this to your needs.</li>
</ul>

<h2>Section 2</h2>

<p>Any HTML content can go here.</p>

Here is an image:
<br />
<img
src="/pages/gg-logo.png"
alt="Gloo Gateway Logo"
style="
width: 50px;
padding: 5px;
border-radius: 8px;
margin: 20px 0px;
background: white;
border: 2px solid #d6d6d6;
"
/>

<br />
<button onclick="alert('Anything in an HTML iframe is supported here!')">
Click me!
</button>
</body>
</html>
37 changes: 37 additions & 0 deletions projects/ui/public/pages/markdown-example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Example Markdown Page (#)

This is a custom Markdown page test.

## Section 1 (##)

- Supports bullet points
- Supports bullet points

### 1.1 (###)

Testing that **Bold works** here.

#### 1.1.1 (####)

Testing that _Italics works_ here.

##### 1.1.1 (#####)

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;
}
```
Original file line number Diff line number Diff line change
@@ -1,25 +1,7 @@
import { css } from "@emotion/react";
import styled from "@emotion/styled";
import { Box } from "@mantine/core";
import Markdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { ApiVersion } from "../../../../Apis/api-types";
import { CardStyles } from "../../../../Styles/shared/Card.style";

const MarkdownOuterContainer = styled.div(
({ theme }) => 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,
Expand All @@ -29,11 +11,7 @@ const DocsTabContent = ({
return (
<Box pb={"60px"}>
<CardStyles.Card>
<MarkdownOuterContainer>
<Markdown remarkPlugins={[remarkGfm]}>
{selectedApiVersion.documentation}
</Markdown>
</MarkdownOuterContainer>
<MarkdownRenderer markdown={selectedApiVersion.documentation} />
</CardStyles.Card>
</Box>
);
Expand Down
23 changes: 13 additions & 10 deletions projects/ui/src/Components/App.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -15,17 +16,19 @@ export function App() {
return (
<ThemeProvider theme={defaultTheme}>
<Global styles={globalStyles} />
<AppContextProvider>
<PortalServerTypeChecker />
<AppUtilsContextProvider>
<AppContextProvider>
<PortalServerTypeChecker />

<MantineProvider
withGlobalStyles
withNormalizeCSS
theme={mantineThemeOverride}
>
<AppContent />
</MantineProvider>
</AppContextProvider>
<MantineProvider
withGlobalStyles
withNormalizeCSS
theme={mantineThemeOverride}
>
<AppContent />
</MantineProvider>
</AppContextProvider>
</AppUtilsContextProvider>
</ThemeProvider>
);
}
19 changes: 19 additions & 0 deletions projects/ui/src/Components/AppContentRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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";
Expand Down Expand Up @@ -173,6 +176,22 @@ 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>
}
/>
</>
))}
</Routes>

<Footer />
Expand Down
81 changes: 81 additions & 0 deletions projects/ui/src/Components/Common/MarkdownRenderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { css } from "@emotion/react";
import styled from "@emotion/styled";
import hljs from "highlight.js";
import { useEffect, useRef } from "react";
import Markdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { borderRadiusConstants } from "../../Styles/constants";

export const MarkdownOuterContainer = styled.div(
({ theme }) => css`
padding: 30px;
* {
margin: revert;
padding: revert;
font-family: revert;
font-weight: revert;
}
blockquote p {
color: ${theme.augustGrey};
}
pre:has(code) {
padding: 1rem 2rem;
border-radius: ${borderRadiusConstants.small};
width: 100%;
background-color: #1c1b1b;
}
em {
font-style: italic;
}
a {
text-decoration: underline;
}
h1 {
font-size: 2rem;
}
h2 {
font-size: 1.7rem;
}
h3 {
font-size: 1.5rem;
}
h4 {
font-size: 1.2rem;
}
h5 {
font-size: 1rem;
}
`
);

const MarkdownRenderer = ({ markdown }: { markdown: string }) => {
const mdContainerRef = useRef<HTMLDivElement | null>(null);

// Highlight the content when it's rendered.
useEffect(() => {
if (!markdown || !mdContainerRef.current) {
return;
}
// Highlight each code element.
// This is faster than doing `hljs.highlightAll()`.
const codeElements = mdContainerRef.current.querySelectorAll("code");
for (let i = 0; i < codeElements.length; i++) {
hljs.highlightElement(codeElements[i]);
}
return () => {
// If this "data-highlighted" attribute isn't reset, it may not
// highlight the code correctly when the page is revisited.
for (let i = 0; i < codeElements.length; i++) {
codeElements[i]?.removeAttribute("data-highlighted");
}
};
}, [markdown, mdContainerRef.current]);

return (
<MarkdownOuterContainer ref={mdContainerRef}>
<Markdown remarkPlugins={[remarkGfm]}>{markdown}</Markdown>
</MarkdownOuterContainer>
);
};

export default MarkdownRenderer;
29 changes: 29 additions & 0 deletions projects/ui/src/Components/CustomPage/Content/CustomHtmlPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useContext } from "react";
import { AppUtilsContext } from "../../../Context/AppUtilsContext";
import { CustomPage } from "../../../user_variables.tmplr";
import { footerHeightPx } from "../../Structure/Footer";
import { headerHeightPx } from "../../Structure/Header.style";

const CustomHtmlPage = ({
customPage,
customPageUrl,
}: {
customPage: CustomPage;
customPageUrl: string;
}) => {
const { windowInnerWidth, windowInnerHeight } = useContext(AppUtilsContext);

return (
<iframe
title={customPage.title}
style={{
width: `${windowInnerWidth}px`,
height: `${windowInnerHeight - footerHeightPx - headerHeightPx}px`,
position: "fixed",
}}
src={customPageUrl}
/>
);
};

export default CustomHtmlPage;
Loading
Loading