Skip to content

feat: branding customization #263

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
18 changes: 11 additions & 7 deletions src/js/components/Search/SearchResultsPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Button, Card, Col, Row, Table, type TableColumnsType, type TableProps,
import { ExportOutlined, LeftOutlined } from '@ant-design/icons';
import { PieChart } from 'bento-charts';

import { PORTAL_URL } from '@/config';
import { PORTAL_URL, SHOW_PORTAL_LINK } from '@/config';
import { T_PLURAL_COUNT } from '@/constants/i18n';
import { BOX_SHADOW, PIE_CHART_HEIGHT } from '@/constants/overviewConstants';
import { useTranslationFn } from '@/hooks';
Expand Down Expand Up @@ -52,12 +52,16 @@ const SearchResultsPane = ({
// TODO: implement these when we have this information in search results:
// ...(!selectedScope.scope.project ? [{ title: 'Project', key: 'project' }] : []),
// ...(!selectedScope.scope.dataset ? [{ title: 'Dataset', key: 'dataset' }] : []),
{
title: '',
key: 'actions',
width: 32,
render: ({ id }) => <IndividualPortalLink id={id} />,
},
...(SHOW_PORTAL_LINK
? ([
{
title: '',
key: 'actions',
width: 32,
render: ({ id }) => <IndividualPortalLink id={id} />,
},
] as TableColumnsType<IndividualResultRow>)
: []),
],
[]
);
Expand Down
7 changes: 4 additions & 3 deletions src/js/components/SiteHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const SiteHeader = () => {
const performSignOut = usePerformSignOut();
const performSignIn = usePerformAuth();

document.title = CLIENT_NAME && CLIENT_NAME.trim() ? `Bento: ${CLIENT_NAME}` : 'Bento';
document.title = CLIENT_NAME && CLIENT_NAME.trim() ? t(CLIENT_NAME) : 'Bento';

const changeLanguage = () => {
const newLang = LNG_CHANGE[i18n.language];
Expand All @@ -49,6 +49,7 @@ const SiteHeader = () => {
[navigate, i18n.language, scopeObj]
);

// TODO: make branding height configurable
return (
<Header id="site-header">
<Flex align="center" justify="space-between">
Expand Down Expand Up @@ -77,12 +78,12 @@ const SiteHeader = () => {
<img
src="/public/assets/branding.png"
alt="logo"
style={{ height: '32px', verticalAlign: 'middle', transform: 'translateY(-3px)', paddingLeft: '4px' }}
style={{ height: '55px', verticalAlign: 'middle', transform: 'translateY(-3px)', paddingLeft: '4px' }}
onClick={navigateToOverview}
/>
)}
<Typography.Title level={1} type="secondary">
{CLIENT_NAME}
{t(CLIENT_NAME)}
</Typography.Title>
</Space>

Expand Down
16 changes: 12 additions & 4 deletions src/js/components/SiteSider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import { ArrowLeftOutlined } from '@ant-design/icons';

import { useSelectedScope } from '@/features/metadata/hooks';
import { useSearchQuery } from '@/features/search/hooks';
import { useTranslationFn } from '@/hooks';
import { useHasScopePermission, useTranslationFn } from '@/hooks';
import { useGetRouteTitleAndIcon, useIsInCatalogueMode, useNavigateToRoot } from '@/hooks/navigation';
import { BentoRoute, TOP_LEVEL_ONLY_ROUTES } from '@/types/routes';
import { buildQueryParamsUrl } from '@/utils/search';
import { getCurrentPage } from '@/utils/router';
import { useCanSeeCensoredCounts } from '@/hooks/censorship';

const { Sider } = Layout;

Expand All @@ -29,6 +30,10 @@ const SiteSider = ({ collapsed, setCollapsed }: { collapsed: boolean; setCollaps
const catalogueMode = useIsInCatalogueMode();
const currentPage = getCurrentPage();

// quick and dirty for demo, to improve
const {hasPermission: hasViewProjectPermission} = useHasScopePermission('view:project');
const canSeeCensoredCounts = useCanSeeCensoredCounts()

const navigateToRoot = useNavigateToRoot();
const { fixedProject, scope, scopeSet } = useSelectedScope();

Expand Down Expand Up @@ -67,15 +72,18 @@ const SiteSider = ({ collapsed, setCollapsed }: { collapsed: boolean; setCollaps
const menuItems: MenuItem[] = useMemo(() => {
const items = [
createMenuItem(BentoRoute.Overview, ...getRouteTitleAndIcon(BentoRoute.Overview)),
createMenuItem(BentoRoute.Search, ...getRouteTitleAndIcon(BentoRoute.Search)),
];

if (canSeeCensoredCounts && hasViewProjectPermission) {
items.push(createMenuItem(BentoRoute.Search, ...getRouteTitleAndIcon(BentoRoute.Search)))
}

if (scope.project) {
// Only show provenance if we're not at the top level, since the giant list of context-less datasets is confusing.
items.push(createMenuItem(BentoRoute.Provenance, ...getRouteTitleAndIcon(BentoRoute.Provenance)));
}

if (BentoRoute.Beacon) {
if (BentoRoute.Beacon && canSeeCensoredCounts && hasViewProjectPermission) {
items.push(createMenuItem(BentoRoute.Beacon, ...getRouteTitleAndIcon(BentoRoute.Beacon)));
}

Expand All @@ -84,7 +92,7 @@ const SiteSider = ({ collapsed, setCollapsed }: { collapsed: boolean; setCollaps
}

return items;
}, [getRouteTitleAndIcon, createMenuItem, scope, fixedProject]);
}, [getRouteTitleAndIcon, createMenuItem, scope, fixedProject, canSeeCensoredCounts, hasViewProjectPermission]);

return (
<Sider
Expand Down
13 changes: 10 additions & 3 deletions src/js/features/beacon/beacon.store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
import axios, { type AxiosRequestConfig } from 'axios';
import { authorizedRequestConfig } from '@/utils/requests';

import { EMPTY_DISCOVERY_RESULTS } from '@/constants/searchConstants';
Expand Down Expand Up @@ -28,9 +28,16 @@ import {
// config response is not scoped
export const getBeaconConfig = createAsyncThunk<BeaconConfigResponse, void, { state: RootState; rejectValue: string }>(
'beacon/getBeaconConfig',
(_, { rejectWithValue }) => {
(_, { getState, rejectWithValue }) => {
const token = getState().auth.accessToken;
const reqConf: AxiosRequestConfig = {};
if (token) {
reqConf.headers = {
Authorization: `Bearer ${token}`,
};
}
return axios
.get(BEACON_INFO_ENDPOINT)
.get(BEACON_INFO_ENDPOINT, reqConf)
.then((res) => res.data)
.catch(printAPIError(rejectWithValue));
},
Expand Down
9 changes: 6 additions & 3 deletions src/js/features/metadata/metadata.store.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';
import axios, { type AxiosRequestConfig } from 'axios';
import type { PaginatedResponse, Project } from '@/types/metadata';
import { RequestStatus } from '@/types/requests';
import type { RootState } from '@/store';
import { printAPIError } from '@/utils/error.util';
import { validProjectDataset } from '@/utils/router';
import { projectsUrl } from '@/constants/configConstants';
import { authorizedRequestConfig } from '@/utils/requests';

export type DiscoveryScope = { project?: string; dataset?: string };

Expand Down Expand Up @@ -43,9 +44,11 @@ export const getProjects = createAsyncThunk<
{ state: RootState; rejectValue: string }
>(
'metadata/getProjects',
(_, { rejectWithValue }) => {
(_, { getState, rejectWithValue }) => {
authorizedRequestConfig(getState())
const reqConf: AxiosRequestConfig = authorizedRequestConfig(getState());
return axios
.get(projectsUrl)
.get(projectsUrl, reqConf)
Copy link
Member

Choose a reason for hiding this comment

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

there is already a helper for this: authorizedRequestConfig(getState())

.then((res) => res.data)
.catch(printAPIError(rejectWithValue));
},
Expand Down
16 changes: 15 additions & 1 deletion src/js/hooks/censorship.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { queryData } from 'bento-auth-js';
import { queryData, queryDatasetLevelBoolean, queryDatasetLevelCounts, queryProjectLevelBoolean, queryProjectLevelCounts } from 'bento-auth-js';
import { useConfig } from '@/features/config/hooks';
import { useHasScopePermission } from '@/hooks';
import { useMemo } from 'react';

export const useCanSeeUncensoredCounts = () => {
const { hasPermission: queryDataPerm } = useHasScopePermission(queryData);
Expand All @@ -11,3 +12,16 @@ export const useCanSeeUncensoredCounts = () => {
// then this becomes true.
return queryDataPerm || countThreshold <= 1;
};


export const useCanSeeCensoredCounts = () => {
const { hasPermission: qDsBools } = useHasScopePermission(queryDatasetLevelBoolean);
const { hasPermission: qDsCounts } = useHasScopePermission(queryDatasetLevelCounts);
const { hasPermission: qProjBools } = useHasScopePermission(queryProjectLevelBoolean);
const { hasPermission: qProjCounts } = useHasScopePermission(queryProjectLevelCounts);

return useMemo(
() => (qDsBools || qDsCounts || qProjBools || qProjCounts),
[qDsBools, qDsCounts, qProjBools, qProjCounts]
)
}
Loading