diff --git a/app/assets/css/app.css b/app/assets/css/app.css
index 4ae31fb5e..553173254 100644
--- a/app/assets/css/app.css
+++ b/app/assets/css/app.css
@@ -44,11 +44,6 @@ body,
white-space: normal !important;
}
-.logo {
- display: inline;
- max-width: 155px;
- max-height: 55px;
-}
.legend .title {
padding: 0 0.3em;
margin: 0.5em;
diff --git a/app/assets/ico/logomark.svg b/app/assets/ico/logomark.svg
new file mode 100644
index 000000000..b7679d482
--- /dev/null
+++ b/app/assets/ico/logomark.svg
@@ -0,0 +1,35 @@
+
diff --git a/app/portainer/services/api/status.service.ts b/app/portainer/services/api/status.service.ts
index 6c838b3fe..8e3190d6b 100644
--- a/app/portainer/services/api/status.service.ts
+++ b/app/portainer/services/api/status.service.ts
@@ -65,6 +65,10 @@ export async function getVersionStatus() {
}
}
+export function useVersionStatus() {
+ return useQuery(['version'], () => getVersionStatus());
+}
+
function buildUrl(action?: string) {
let url = '/status';
diff --git a/app/react/components/buttons/Button.css b/app/react/components/buttons/Button.css
index 49edbbf3c..aaaf34a79 100644
--- a/app/react/components/buttons/Button.css
+++ b/app/react/components/buttons/Button.css
@@ -2,7 +2,7 @@
padding: 0;
margin: 0;
background-color: transparent;
- width: 1em;
+ border: 0;
}
.btn-none:focus {
diff --git a/app/react/sidebar/Footer.tsx b/app/react/sidebar/Footer.tsx
deleted file mode 100644
index 4ea94c05c..000000000
--- a/app/react/sidebar/Footer.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-import { useState } from 'react';
-import { useQuery } from 'react-query';
-import clsx from 'clsx';
-import { Database, Hash, Server, Tag, Tool } from 'react-feather';
-import { DialogOverlay } from '@reach/dialog';
-
-import {
- getStatus,
- getVersionStatus,
-} from '@/portainer/services/api/status.service';
-
-import { Button } from '@@/buttons';
-
-import { UpdateNotification } from './UpdateNotifications';
-import styles from './Footer.module.css';
-import '@reach/dialog/styles.css';
-
-export function Footer() {
- const [showBuildInfo, setShowBuildInfo] = useState(false);
- const statusQuery = useStatus();
- const versionQuery = useVersionStatus();
-
- if (!statusQuery.data || !versionQuery.data) {
- return null;
- }
-
- const { Edition, Version } = statusQuery.data;
- const { ServerVersion, DatabaseVersion, Build } = versionQuery.data;
-
- function toggleModal() {
- setShowBuildInfo(!showBuildInfo);
- }
-
- return (
- <>
-
-
-
-
-
-
Portainer {Edition}
-
-
-
-
-
-
-
-
-
- Server Version: {ServerVersion}
-
- |
-
-
-
- Database Version: {DatabaseVersion}
-
- |
-
-
-
-
-
- CI Build Number: {Build.BuildNumber}
-
- |
-
-
-
- Image Tag: {Build.ImageTag}
-
- |
-
-
-
-
-
-
-
- Compilation tools:
-
-
-
-
- Nodejs v{Build.NodejsVersion}
-
-
- Yarn v{Build.YarnVersion}
-
-
- Webpack v{Build.WebpackVersion}
-
-
- Go v{Build.GoVersion}
-
-
-
-
-
-
-
-
-
-
-
-
- {process.env.PORTAINER_EDITION === 'CE' &&
}
-
-
©
-
Portainer {Edition}
-
-
- {Version}
-
-
- {process.env.PORTAINER_EDITION === 'CE' && (
-
- Upgrade
-
- )}
-
-
- >
- );
-}
-
-function useStatus() {
- return useQuery(['status'], () => getStatus());
-}
-
-function useVersionStatus() {
- return useQuery(['version'], () => getVersionStatus());
-}
diff --git a/app/react/sidebar/Footer/BuildInfoModal.tsx b/app/react/sidebar/Footer/BuildInfoModal.tsx
new file mode 100644
index 000000000..1a550cc92
--- /dev/null
+++ b/app/react/sidebar/Footer/BuildInfoModal.tsx
@@ -0,0 +1,126 @@
+import { useState } from 'react';
+import { Database, Hash, Server, Tag, Tool } from 'react-feather';
+import { DialogOverlay } from '@reach/dialog';
+
+import {
+ useStatus,
+ useVersionStatus,
+} from '@/portainer/services/api/status.service';
+
+import { Button } from '@@/buttons';
+
+import styles from './Footer.module.css';
+
+export function BuildInfoModalButton() {
+ const [isBuildInfoVisible, setIsBuildInfoVisible] = useState(false);
+ const statusQuery = useStatus();
+
+ if (!statusQuery.data) {
+ return null;
+ }
+
+ const { Version } = statusQuery.data;
+
+ return (
+ <>
+
+ {isBuildInfoVisible && (
+ setIsBuildInfoVisible(false)} />
+ )}
+ >
+ );
+}
+
+function BuildInfoModal({ closeModal }: { closeModal: () => void }) {
+ const versionQuery = useVersionStatus();
+ const statusQuery = useStatus();
+
+ if (!statusQuery.data || !versionQuery.data) {
+ return null;
+ }
+
+ const { Edition } = statusQuery.data;
+ const { ServerVersion, DatabaseVersion, Build } = versionQuery.data;
+
+ return (
+
+
+
+
+
+
Portainer {Edition}
+
+
+
+
+
+
+
+
+
+ Server Version: {ServerVersion}
+
+ |
+
+
+
+ Database Version: {DatabaseVersion}
+
+ |
+
+
+
+
+
+ CI Build Number: {Build.BuildNumber}
+
+ |
+
+
+
+ Image Tag: {Build.ImageTag}
+
+ |
+
+
+
+
+
+
+
+ Compilation tools:
+
+
+
+
+ Nodejs v{Build.NodejsVersion}
+
+
+ Yarn v{Build.YarnVersion}
+
+
+ Webpack v{Build.WebpackVersion}
+
+ Go v{Build.GoVersion}
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/react/sidebar/Footer.module.css b/app/react/sidebar/Footer/Footer.module.css
similarity index 100%
rename from app/react/sidebar/Footer.module.css
rename to app/react/sidebar/Footer/Footer.module.css
diff --git a/app/react/sidebar/Footer/Footer.tsx b/app/react/sidebar/Footer/Footer.tsx
new file mode 100644
index 000000000..dd19ce370
--- /dev/null
+++ b/app/react/sidebar/Footer/Footer.tsx
@@ -0,0 +1,59 @@
+import { PropsWithChildren } from 'react';
+import clsx from 'clsx';
+
+import { isBE } from '@/portainer/feature-flags/feature-flags.service';
+
+import { UpdateNotification } from './UpdateNotifications';
+import { BuildInfoModalButton } from './BuildInfoModal';
+import '@reach/dialog/styles.css';
+import styles from './Footer.module.css';
+import Logo from './portainer_logo.svg?c';
+
+export function Footer() {
+ return isBE ? : ;
+}
+
+function CEFooter() {
+ return (
+
+ );
+}
+
+function BEFooter() {
+ return (
+
+
+ ©
+ Portainer Business Edition
+
+
+
+
+ );
+}
+
+function FooterContent({ children }: PropsWithChildren) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/react/sidebar/UpdateNotifications.module.css b/app/react/sidebar/Footer/UpdateNotifications.module.css
similarity index 100%
rename from app/react/sidebar/UpdateNotifications.module.css
rename to app/react/sidebar/Footer/UpdateNotifications.module.css
diff --git a/app/react/sidebar/UpdateNotifications.tsx b/app/react/sidebar/Footer/UpdateNotifications.tsx
similarity index 100%
rename from app/react/sidebar/UpdateNotifications.tsx
rename to app/react/sidebar/Footer/UpdateNotifications.tsx
diff --git a/app/react/sidebar/Footer/index.ts b/app/react/sidebar/Footer/index.ts
new file mode 100644
index 000000000..65e2506fa
--- /dev/null
+++ b/app/react/sidebar/Footer/index.ts
@@ -0,0 +1 @@
+export { Footer } from './Footer';
diff --git a/app/react/sidebar/Footer/portainer_logo.svg b/app/react/sidebar/Footer/portainer_logo.svg
new file mode 100644
index 000000000..1bf390370
--- /dev/null
+++ b/app/react/sidebar/Footer/portainer_logo.svg
@@ -0,0 +1,36 @@
+
diff --git a/app/react/sidebar/Header.module.css b/app/react/sidebar/Header.module.css
new file mode 100644
index 000000000..404b9b8d0
--- /dev/null
+++ b/app/react/sidebar/Header.module.css
@@ -0,0 +1,5 @@
+.logo {
+ display: inline;
+ max-height: 55px;
+ max-width: min(100%, 230px);
+}
diff --git a/app/react/sidebar/Header.tsx b/app/react/sidebar/Header.tsx
index 144e3b19a..2fa0ebf3a 100644
--- a/app/react/sidebar/Header.tsx
+++ b/app/react/sidebar/Header.tsx
@@ -1,37 +1,74 @@
import { ChevronsLeft, ChevronsRight } from 'react-feather';
+import clsx from 'clsx';
-import defaultLogo from '@/assets/images/logo_small_alt.png';
+import { isBE } from '@/portainer/feature-flags/feature-flags.service';
+import smallLogo from '@/assets/ico/logomark.svg';
import { Link } from '@@/Link';
+import fullLogoBE from './portainer_logo-BE.svg';
+import fullLogoCE from './portainer_logo-CE.svg';
import { useSidebarState } from './useSidebarState';
+import styles from './Header.module.css';
interface Props {
logo?: string;
}
-export function Header({ logo }: Props) {
+export function Header({ logo: customLogo }: Props) {
const { toggle, isOpen } = useSidebarState();
return (
-
-
-
- {isOpen && 'portainer.io'}
-
+
+
+
+
+
+ {isOpen && customLogo && (
+
+ )}
+
);
}
+
+function getLogo(isOpen: boolean, customLogo?: string) {
+ if (customLogo) {
+ return customLogo;
+ }
+
+ if (!isOpen) {
+ return smallLogo;
+ }
+
+ return isBE ? fullLogoBE : fullLogoCE;
+}
+
+function Logo({
+ customLogo,
+ isOpen,
+}: {
+ customLogo?: string;
+ isOpen: boolean;
+}) {
+ const logo = getLogo(isOpen, customLogo);
+
+ return (
+
+ );
+}
diff --git a/app/react/sidebar/portainer_logo-BE.svg b/app/react/sidebar/portainer_logo-BE.svg
new file mode 100644
index 000000000..ed7ab076d
--- /dev/null
+++ b/app/react/sidebar/portainer_logo-BE.svg
@@ -0,0 +1,51 @@
+
diff --git a/app/react/sidebar/portainer_logo-CE.svg b/app/react/sidebar/portainer_logo-CE.svg
new file mode 100644
index 000000000..7b6c83a00
--- /dev/null
+++ b/app/react/sidebar/portainer_logo-CE.svg
@@ -0,0 +1,68 @@
+