feat: make kafka ui branded

This commit is contained in:
Benedetto Marco Serinelli 2024-02-11 08:44:01 +01:00
parent 9cf310865a
commit 9f2680e564
7 changed files with 89 additions and 22 deletions

View file

@ -26,6 +26,9 @@ public class PreferencesController implements PreferencesApi {
@Value("${kafka.ui.preferences.logo}")
private String kafkaUiIcon;
@Value("${kafka.ui.preferences.version}")
private boolean kafkaUiVersion;
@Override
public Mono<ResponseEntity<ApplicationsPreferencesDTO>> getPreferences(ServerWebExchange exchange) {
@ -35,6 +38,7 @@ public class PreferencesController implements PreferencesApi {
res.setRemoveGitLink(kafkaUiRemovDiscordLink);
res.setLogo(kafkaUiIcon);
res.setFavicon(kafkaUiFavicon);
res.setVersion(kafkaUiVersion);
return Mono.just(
ResponseEntity.ok(res
)

File diff suppressed because one or more lines are too long

View file

@ -2088,6 +2088,9 @@ components:
logo:
type: string
example: "Base 64 icon"
version:
type: boolean
example: "Show version info"
TopicSerdeSuggestion:
type: object
properties:

View file

@ -31,6 +31,7 @@
$favicon.href = jsonResponse.favicon
document.head.appendChild($favicon)
}
document.title = jsonResponse.appName;
});
</script>
<style>

View file

@ -1,4 +1,4 @@
import React, { useContext } from 'react';
import React, { useContext, useState, useEffect } from 'react';
import Select from 'components/common/Select/Select';
import Logo from 'components/common/Logo/Logo';
import Version from 'components/Version/Version';
@ -11,6 +11,7 @@ import { ThemeModeContext } from 'components/contexts/ThemeModeContext';
import UserInfo from './UserInfo/UserInfo';
import * as S from './NavBar.styled';
import { preferencesClient as api } from 'lib/api';
interface Props {
onBurgerClick: () => void;
@ -50,6 +51,31 @@ const options = [
const NavBar: React.FC<Props> = ({ onBurgerClick }) => {
const { themeMode, setThemeMode } = useContext(ThemeModeContext);
const [appName, setAppName] = useState<string>("");
const [showGitHubLink, setShowGitHubLink] = useState<boolean>(true);
const [showDiscordLink, setShowDiscordLink] = useState<boolean>(true);
const [showVersion, setShowVersion] = useState<boolean>(true);
const [logoBase64, setLogoBase64] = useState<string>("");
useEffect(() => {
const fetchPreferences = async () => {
try {
const preferencesData = await api.getPreferences();
setAppName(preferencesData.appName);
setShowGitHubLink(preferencesData.removeGitLink);
setShowDiscordLink(preferencesData.removeDiscordLink);
setShowVersion(preferencesData.version);
if (preferencesData.logo) {
setLogoBase64(preferencesData.logo);
}
} catch (error) {
console.error('Error fetching preferences:', error);
}
};
fetchPreferences();
}, []);
return (
<S.Navbar role="navigation" aria-label="Page Header">
@ -68,13 +94,22 @@ const NavBar: React.FC<Props> = ({ onBurgerClick }) => {
</S.NavbarBurger>
<S.Hyperlink to="/">
<Logo />
UI for Apache Kafka
{logoBase64 ? (
<img src={logoBase64} alt="Logo" />
) : (
<Logo />
)}
{appName ? (
<span>{appName}</span>
) : (
"UI for Apache Kafka"
)}
</S.Hyperlink>
{showVersion && (
<S.NavbarItem>
<Version />
</S.NavbarItem>
)}
</S.NavbarBrand>
</S.NavbarBrand>
<S.NavbarSocial>
@ -84,18 +119,22 @@ const NavBar: React.FC<Props> = ({ onBurgerClick }) => {
onChange={setThemeMode}
isThemeMode
/>
<S.SocialLink
href="https://github.com/provectus/kafka-ui"
target="_blank"
>
<GitIcon />
</S.SocialLink>
{showGitHubLink && (
<S.SocialLink
href="https://github.com/provectus/kafka-ui"
target="_blank"
>
<GitIcon />
</S.SocialLink>
)}
{showDiscordLink && (
<S.SocialLink
href="https://discord.com/invite/4DWzD7pGE5"
target="_blank"
>
<DiscordIcon />
</S.SocialLink>
)}
<UserInfo />
</S.NavbarSocial>
</S.Navbar>

View file

@ -1,23 +1,40 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import WarningIcon from 'components/common/Icons/WarningIcon';
import { gitCommitPath } from 'lib/paths';
import { useLatestVersion } from 'lib/hooks/api/latestVersion';
import { formatTimestamp } from 'lib/dateTimeHelpers';
import { PreferencesApi } from '../../generated-sources';
import * as S from './Version.styled';
import { preferencesClient as api } from 'lib/api';
const Version: React.FC = () => {
const { data: latestVersionInfo = {} } = useLatestVersion();
const { buildTime, commitId, isLatestRelease, version } =
latestVersionInfo.build;
const { versionTag } = latestVersionInfo?.latestRelease || '';
const [showVersion, setShowVersion] = useState(true);
const [latestVersionInfo, setLatestVersionInfo] = useState<any>({});
useEffect(() => {
const fetchLatestVersion = async () => {
try {
const preferencesData = await api.getPreferences();
const latestVersionInfo = preferencesData?.version || {};
setLatestVersionInfo(latestVersionInfo);
setShowVersion(preferencesData?.version || true); // Set showVersion based on the preferences data
} catch (error) {
console.error('Error fetching latest version:', error);
setShowVersion(false); // Set showVersion to false in case of error
}
};
fetchLatestVersion();
}, []);
const { buildTime, commitId, isLatestRelease, version, versionTag } = latestVersionInfo;
const currentVersion =
isLatestRelease && version?.match(versionTag)
? versionTag
: formatTimestamp(buildTime);
return (
return showVersion ? (
<S.Wrapper>
{!isLatestRelease && (
<S.OutdatedWarning
@ -42,7 +59,7 @@ const Version: React.FC = () => {
)}
<S.CurrentVersion>{currentVersion}</S.CurrentVersion>
</S.Wrapper>
);
) : null;
};
export default Version;

View file

@ -11,6 +11,7 @@ import {
AuthorizationApi,
ApplicationConfigApi,
AclsApi,
PreferencesApi
} from 'generated-sources';
import { BASE_PARAMS } from 'lib/constants';
@ -27,3 +28,4 @@ export const consumerGroupsApiClient = new ConsumerGroupsApi(apiClientConf);
export const authApiClient = new AuthorizationApi(apiClientConf);
export const appConfigApiClient = new ApplicationConfigApi(apiClientConf);
export const aclApiClient = new AclsApi(apiClientConf);
export const preferencesClient = new PreferencesApi(apiClientConf);