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 ability to customize logo and title #9052

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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: 4 additions & 0 deletions changelog.d/20250205_141639_klakhov_setup_logo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### Added

- Ability to customize title and logo
(<https://github.com/cvat-ai/cvat/pull/9052>)
2 changes: 2 additions & 0 deletions cvat-core/src/server-response-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ export interface SerializedAbout {
description: string;
name: string;
version: string;
logo: string;
title: string;
}

export interface SerializedRemoteFile {
Expand Down
17 changes: 17 additions & 0 deletions cvat-ui/src/components/common/cvat-logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
klakhov marked this conversation as resolved.
Show resolved Hide resolved
import { useSelector } from 'react-redux';

function CVATLogo(): JSX.Element {
const SVGLogo = useSelector((state: any) => state.about.server.logo);
klakhov marked this conversation as resolved.
Show resolved Hide resolved

return (
<div className='cvat-logo-icon'>
<img
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the server returns logo (let's say 1024x256px)? Will it be fit into the component?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed styles a bit. By default logo component is 64x32 so everything bigger will be scaled using object-fit: contain to maintain the size

src={`data:image/svg+xml;utf8,${encodeURIComponent(SVGLogo)}`}
alt='CVAT Logo'
/>
</div>
);
}

export default React.memo(CVATLogo);
9 changes: 5 additions & 4 deletions cvat-ui/src/components/cvat-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentP
loadServerAPISchema();
}

if (!aboutInitialized && !aboutFetching) {
loadAbout();
return;
}

if (user == null || !user.isVerified || !user.id) {
return;
}
Expand All @@ -337,10 +342,6 @@ class CVATApplication extends React.PureComponent<CVATAppProps & RouteComponentP
loadFormats();
}

if (!aboutInitialized && !aboutFetching) {
loadAbout();
}

if (organizationInitialized && !requestsInitialized && !requestsFetching) {
initRequests();
}
Expand Down
6 changes: 3 additions & 3 deletions cvat-ui/src/components/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { connect } from 'react-redux';
import { useHistory, useLocation } from 'react-router';
import { Row, Col } from 'antd/lib/grid';
import { MenuProps } from 'antd/lib/menu';
import Icon, {
import {
SettingOutlined,
InfoCircleOutlined,
EditOutlined,
Expand All @@ -34,9 +34,9 @@ import notification from 'antd/lib/notification';
import config from 'config';

import { Organization, getCore } from 'cvat-core-wrapper';
import { CVATLogo } from 'icons';
import ChangePasswordDialog from 'components/change-password-modal/change-password-modal';
import CVATTooltip from 'components/common/cvat-tooltip';
import CVATLogo from 'components/common/cvat-logo';
import { switchSettingsModalVisible as switchSettingsModalVisibleAction } from 'actions/settings-actions';
import { logoutAsync, authActions } from 'actions/auth-actions';
import { shortcutsActions, registerComponentShortcuts } from 'actions/shortcuts-actions';
Expand Down Expand Up @@ -430,7 +430,7 @@ function HeaderComponent(props: Props): JSX.Element {
<Layout.Header className='cvat-header'>
<GlobalHotKeys keyMap={subKeyMap(componentShortcuts, keyMap)} handlers={handlers} />
<div className='cvat-left-header'>
<Icon className='cvat-logo-icon' component={CVATLogo} />
<CVATLogo />
<Button
className={getButtonClassName('projects')}
type='link'
Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/src/components/header/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
}
}

.anticon.cvat-logo-icon {
.cvat-logo-icon {
margin: 0 $grid-unit-size * 2;
}

Expand Down
11 changes: 6 additions & 5 deletions cvat-ui/src/components/signing-common/signing-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

import './styles.scss';
import React from 'react';
import { useSelector } from 'react-redux';
import Layout from 'antd/lib/layout';
import { Col, Row } from 'antd/lib/grid';
import { CVATLogo } from 'icons';
import Icon from '@ant-design/icons';
import Title from 'antd/lib/typography/Title';
import CVATLogo from 'components/common/cvat-logo';
import SVGSigningBackground from '../../assets/signing-background.svg';

interface SignInLayoutComponentProps {
Expand Down Expand Up @@ -51,6 +51,8 @@ export const formSizes: FormSizes = {
function SignInLayout(props: SignInLayoutComponentProps): JSX.Element {
const { children } = props;
const { Content, Header } = Layout;
const title = useSelector((state: any) => state.about.server.title);

const titleSizes = {
xs: { span: 0 },
sm: { span: 0 },
Expand All @@ -73,16 +75,15 @@ function SignInLayout(props: SignInLayoutComponentProps): JSX.Element {
<Header className='cvat-signing-header'>
<Row justify='center' align='middle'>
<Col {...logoSizes}>
<Icon className='cvat-logo-icon' component={CVATLogo} />
<CVATLogo />
</Col>
</Row>
</Header>
<Layout className='cvat-signing-layout'>
<Content>
<Row justify='center' align='middle' style={{ height: '100%' }}>
<Col {...titleSizes} className='cvat-signing-title'>
<Title>Open Data</Title>
<Title>Annotation Platform</Title>
<Title>{title}</Title>
</Col>
{children}
</Row>
Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/src/components/signing-common/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ $social-google-background: #4286f5;
width: 100%;

.cvat-logo-icon {
fill: white;
filter: brightness(0) invert(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it makes any logo on sign-in page white, however what if a color logo provided?
This approach will break such logo.

}
}

Expand Down
2 changes: 0 additions & 2 deletions cvat-ui/src/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import React from 'react';

import SVGCVATLogo from './assets/cvat-logo.svg';
import SVGCVATIcon from './assets/cvat-icon.svg';
import SVGCursorIcon from './assets/cursor-icon.svg';
import SVGMoveIcon from './assets/move-icon.svg';
Expand Down Expand Up @@ -72,7 +71,6 @@ import SVGShowGroundTruthIcon from './assets/show-gt-icon.svg';
import SVGJoinIcon from './assets/join-icon.svg';
import SVGSliceIcon from './assets/slice-icon.svg';

export const CVATLogo = React.memo((): JSX.Element => <SVGCVATLogo />);
export const CVATIcon = React.memo((): JSX.Element => <SVGCVATIcon />);
export const CursorIcon = React.memo((): JSX.Element => <SVGCursorIcon />);
export const MoveIcon = React.memo((): JSX.Element => <SVGMoveIcon />);
Expand Down
File renamed without changes
2 changes: 2 additions & 0 deletions cvat/apps/engine/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2627,6 +2627,8 @@ class AboutSerializer(serializers.Serializer):
name = serializers.CharField(max_length=128)
description = serializers.CharField(max_length=2048)
version = serializers.CharField(max_length=64)
logo = serializers.CharField()
title = serializers.CharField(max_length=1024)

class FrameMetaSerializer(serializers.Serializer):
width = serializers.IntegerField()
Expand Down
18 changes: 10 additions & 8 deletions cvat/apps/engine/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@
_DATA_UPDATED_DATE_HEADER_NAME = 'X-Updated-Date'
_RETRY_AFTER_TIMEOUT = 10

ICON_FILE = "assets/logo.svg"
klakhov marked this conversation as resolved.
Show resolved Hide resolved

def get_logo() -> str:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check that we don't read it on every about request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed implementation to use static logo file as Roman suggested. Now it should be cached correctly

with open(osp.join(osp.dirname(__file__), ICON_FILE)) as f:
return f.read()
bsekachev marked this conversation as resolved.
Show resolved Hide resolved

@extend_schema(tags=['server'])
class ServerViewSet(viewsets.ViewSet):
serializer_class = None
Expand All @@ -210,15 +216,11 @@ def get_serializer(self, *args, **kwargs):
def about(request):
from cvat import __version__ as cvat_version
about = {
"name": "Computer Vision Annotation Tool",
"name": settings.ABOUT_INFO["name"],
bsekachev marked this conversation as resolved.
Show resolved Hide resolved
"title": settings.ABOUT_INFO["title"],
"description": settings.ABOUT_INFO["description"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you make the name and description customizable? I don't think that was in the customer's request. It's also not mentioned in the changelog.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me it makes sense if we want to customize the /about response via settings we can also customize those fields.

"version": cvat_version,
"description": "CVAT is completely re-designed and re-implemented " +
"version of Video Annotation Tool from Irvine, California " +
"tool. It is free, online, interactive video and image annotation " +
"tool for computer vision. It is being used by our team to " +
"annotate million of objects with different properties. Many UI " +
"and UX decisions are based on feedbacks from professional data " +
"annotation team."
"logo": get_logo(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to include the whole logo into the API response?

I think it would be more sensible to include the URL of the logo, and stick the actual logo in the static directory. Then:

  1. The API response won't be as bloated.
  2. The usual HTTP caching mechanisms will apply, so the clients won't fetch the logo more often than necessary.
  3. It'll be more efficient if the logo is in a non-text format (e.g. PNG), since no encoding will be necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, implemented this approach

}
serializer = AboutSerializer(data=about)
if serializer.is_valid(raise_exception=True):
Expand Down
7 changes: 7 additions & 0 deletions cvat/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6905,9 +6905,16 @@ components:
version:
type: string
maxLength: 64
logo:
type: string
title:
type: string
maxLength: 1024
required:
- description
- logo
- name
- title
- version
AcceptInvitationRead:
type: object
Expand Down
12 changes: 12 additions & 0 deletions cvat/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -769,3 +769,15 @@ class CVAT_QUEUES(Enum):

# Indicates the maximum number of days a file or directory is retained in the temporary directory
TMP_FILE_OR_DIR_RETENTION_DAYS = 3

ABOUT_INFO = {
"name": "Computer Vision Annotation Tool",
"title": "Open Data Annotation Platform",
klakhov marked this conversation as resolved.
Show resolved Hide resolved
"description": "CVAT is completely re-designed and re-implemented " +
"version of Video Annotation Tool from Irvine, California " +
"tool. It is free, online, interactive video and image annotation " +
"tool for computer vision. It is being used by our team to " +
"annotate million of objects with different properties. Many UI " +
"and UX decisions are based on feedbacks from professional data " +
"annotation team.",
bsekachev marked this conversation as resolved.
Show resolved Hide resolved
}
Loading