chore(ui): customize landing page improvements (#13557)

* CustomizePageClassBase class improvements

* updated the reset button
reordered customize page option on setting page

* localization change for other languages

* added functionality to choose the widget size and updated widget content according to the sizes

* styling fix

* fixed double API calls on my data page and flakiness in showing loader for feeds widget

* fixed code smell
This commit is contained in:
Aniket Katkar 2023-10-14 00:52:06 +05:30 committed by GitHub
parent 2ef49d52ca
commit 53629c8cc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 474 additions and 310 deletions

View File

@ -19,5 +19,21 @@ export interface AddWidgetModalProps {
placeholderWidgetKey: string;
addedWidgetsList: Array<string>;
handleCloseAddWidgetModal: () => void;
handleAddWidget: (widget: Document, widgetKey: string) => void;
handleAddWidget: (
widget: Document,
widgetKey: string,
widgetSize: number
) => void;
}
export interface AddWidgetTabContentProps {
widget: Document;
maxGridSizeSupport: number;
getAddWidgetHandler: (widget: Document, widgetSize: number) => () => void;
widgetSizeOptions: Array<WidgetSizeInfo>;
}
export interface WidgetSizeInfo {
label: string;
value: number;
}

View File

@ -11,19 +11,8 @@
* limitations under the License.
*/
import { CheckOutlined, PlusOutlined } from '@ant-design/icons';
import {
Button,
Col,
Image,
Modal,
Row,
Space,
Tabs,
TabsProps,
Tooltip,
Typography,
} from 'antd';
import { CheckOutlined } from '@ant-design/icons';
import { Modal, Space, Tabs, TabsProps } from 'antd';
import { AxiosError } from 'axios';
import { isEmpty } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
@ -32,11 +21,14 @@ import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum';
import { WidgetWidths } from '../../../enums/CustomizablePage.enum';
import { Document } from '../../../generated/entity/docStore/document';
import { getAllKnowledgePanels } from '../../../rest/DocStoreAPI';
import { CustomizePageClassBase } from '../../../utils/CustomizePageClassBase';
import { showErrorToast } from '../../../utils/ToastUtils';
import ErrorPlaceHolder from '../../common/error-with-placeholder/ErrorPlaceHolder';
import { AddWidgetModalProps } from './AddWidgetModal.interface';
import {
AddWidgetModalProps,
WidgetSizeInfo,
} from './AddWidgetModal.interface';
import './AddWidgetModal.less';
import AddWidgetTabContent from './AddWidgetTabContent';
function AddWidgetModal({
open,
@ -62,29 +54,19 @@ function AddWidgetModal({
}, []);
const getAddWidgetHandler = useCallback(
(widget: Document) => () => handleAddWidget(widget, placeholderWidgetKey),
(widget: Document, widgetSize: number) => () =>
handleAddWidget(widget, placeholderWidgetKey, widgetSize),
[handleAddWidget, placeholderWidgetKey]
);
const checkAddWidgetValidity = useCallback(
(widget: Document) => {
const gridSizes = widget.data.gridSizes;
const gridSizesInNumbers: Array<number> = gridSizes.map(
(size: WidgetWidths) => WidgetWidths[size]
);
return gridSizesInNumbers.every((size) => size <= maxGridSizeSupport);
},
[widgetsList]
);
const tabItems: TabsProps['items'] = useMemo(
() =>
widgetsList?.map((widget) => {
const widgetAddable = checkAddWidgetValidity(widget);
const widgetImage = CustomizePageClassBase.getWidgetImageFromKey(
widget.fullyQualifiedName
);
const widgetSizeOptions: Array<WidgetSizeInfo> =
widget.data.gridSizes.map((size: WidgetWidths) => ({
label: size,
value: WidgetWidths[size],
}));
return {
label: (
@ -102,36 +84,16 @@ function AddWidgetModal({
),
key: widget.fullyQualifiedName,
children: (
<Row align="middle" className="h-min-480" justify="center">
<Col>
<Space align="center" direction="vertical">
<Image className="p-y-md" preview={false} src={widgetImage} />
<Typography.Paragraph className="d-block text-center">
{widget.description}
</Typography.Paragraph>
<Tooltip
placement="bottom"
title={
widgetAddable ? '' : t('message.can-not-add-widget')
}>
<Button
ghost
className="p-x-lg m-t-md"
data-testid="add-widget-placeholder-button"
disabled={!widgetAddable}
icon={<PlusOutlined />}
type="primary"
onClick={getAddWidgetHandler(widget)}>
{t('label.add')}
</Button>
</Tooltip>
</Space>
</Col>
</Row>
<AddWidgetTabContent
getAddWidgetHandler={getAddWidgetHandler}
maxGridSizeSupport={maxGridSizeSupport}
widget={widget}
widgetSizeOptions={widgetSizeOptions}
/>
),
};
}),
[widgetsList, addedWidgetsList, checkAddWidgetValidity, getAddWidgetHandler]
[widgetsList, addedWidgetsList, getAddWidgetHandler, maxGridSizeSupport]
);
useEffect(() => {

View File

@ -0,0 +1,103 @@
/*
* Copyright 2023 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { PlusOutlined } from '@ant-design/icons';
import {
Button,
Col,
Image,
Radio,
RadioChangeEvent,
Row,
Space,
Tooltip,
Typography,
} from 'antd';
import React, { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import customizePageClassBase from '../../../utils/CustomizePageClassBase';
import { AddWidgetTabContentProps } from './AddWidgetModal.interface';
function AddWidgetTabContent({
getAddWidgetHandler,
maxGridSizeSupport,
widget,
widgetSizeOptions,
}: Readonly<AddWidgetTabContentProps>) {
const { t } = useTranslation();
const [selectedWidgetSize, setSelectedWidgetSize] = useState<number>(
widgetSizeOptions[0].value
);
const widgetAddable = useMemo(
() => selectedWidgetSize <= maxGridSizeSupport,
[selectedWidgetSize, maxGridSizeSupport]
);
const widgetImage = useMemo(
() =>
customizePageClassBase.getWidgetImageFromKey(
widget.fullyQualifiedName,
selectedWidgetSize
),
[widget, selectedWidgetSize]
);
const handleSizeChange = useCallback((e: RadioChangeEvent) => {
setSelectedWidgetSize(e.target.value);
}, []);
return (
<Row>
<Col span={24}>
<Space>
<Typography.Text>{`${t('label.size')}:`}</Typography.Text>
<Radio.Group
defaultValue={selectedWidgetSize}
optionType="button"
options={widgetSizeOptions}
onChange={handleSizeChange}
/>
</Space>
</Col>
<Col span={24}>
<Row className="h-min-480" justify="center">
<Col>
<Space align="center" direction="vertical">
<Image className="p-y-md" preview={false} src={widgetImage} />
<Typography.Paragraph className="d-block text-center">
{widget.description}
</Typography.Paragraph>
<Tooltip
placement="bottom"
title={widgetAddable ? '' : t('message.can-not-add-widget')}>
<Button
ghost
className="p-x-lg m-t-md"
data-testid="add-widget-placeholder-button"
disabled={!widgetAddable}
icon={<PlusOutlined />}
type="primary"
onClick={getAddWidgetHandler(widget, selectedWidgetSize)}>
{t('label.add')}
</Button>
</Tooltip>
</Space>
</Col>
</Row>
</Col>
</Row>
);
}
export default AddWidgetTabContent;

View File

@ -11,7 +11,7 @@
* limitations under the License.
*/
import { Button, Col, Row, Space, Typography } from 'antd';
import { Button, Col, Modal, Row, Space, Typography } from 'antd';
import { AxiosError } from 'axios';
import classNames from 'classnames';
import { isEmpty, isNil, uniqBy } from 'lodash';
@ -21,12 +21,6 @@ import { useTranslation } from 'react-i18next';
import { Link, useHistory, useLocation, useParams } from 'react-router-dom';
import AppState from '../../../AppState';
import gridBgImg from '../../../assets/img/grid-bg-img.png';
import {
LANDING_PAGE_LAYOUT,
LANDING_PAGE_MAX_GRID_SIZE,
LANDING_PAGE_ROW_HEIGHT,
LANDING_PAGE_WIDGET_MARGIN,
} from '../../../constants/CustomizePage.constants';
import {
GlobalSettingOptions,
GlobalSettingsMenuCategory,
@ -48,7 +42,7 @@ import {
getLayoutUpdateHandler,
getRemoveWidgetHandler,
} from '../../../utils/CustomizableLandingPageUtils';
import { CustomizePageClassBase } from '../../../utils/CustomizePageClassBase';
import customizePageClassBase from '../../../utils/CustomizePageClassBase';
import {
getPersonaDetailsPath,
getSettingPath,
@ -75,7 +69,8 @@ function CustomizeMyData({
const [resetRightPanelLayout, setResetRightPanelLayout] =
useState<boolean>(false);
const [layout, setLayout] = useState<Array<WidgetConfig>>([
...(initialPageData.data?.page?.layout ?? LANDING_PAGE_LAYOUT),
...(initialPageData.data?.page?.layout ??
customizePageClassBase.landingPageDefaultLayout),
{
h: 2,
i: LandingPageWidgetKeys.EMPTY_WIDGET_PLACEHOLDER,
@ -89,6 +84,7 @@ function CustomizeMyData({
LandingPageWidgetKeys.EMPTY_WIDGET_PLACEHOLDER
);
const [isWidgetModalOpen, setIsWidgetModalOpen] = useState<boolean>(false);
const [isResetModalOpen, setIsResetModalOpen] = useState<boolean>(false);
const { isAuthDisabled } = useAuth(location.pathname);
const [followedData, setFollowedData] = useState<Array<EntityReference>>();
const [followedDataCount, setFollowedDataCount] = useState(0);
@ -124,12 +120,17 @@ function CustomizeMyData({
}, []);
const handleAddWidget = useCallback(
(newWidgetData: Document, placeholderWidgetKey: string) => {
(
newWidgetData: Document,
placeholderWidgetKey: string,
widgetSize: number
) => {
setLayout(
getAddWidgetHandler(
newWidgetData,
placeholderWidgetKey,
LANDING_PAGE_MAX_GRID_SIZE
widgetSize,
customizePageClassBase.landingPageMaxGridSize
)
);
setIsWidgetModalOpen(false);
@ -146,6 +147,14 @@ function CustomizeMyData({
[layout]
);
const handleOpenResetModal = useCallback(() => {
setIsResetModalOpen(true);
}, []);
const handleCloseResetModal = useCallback(() => {
setIsResetModalOpen(false);
}, []);
const handleOpenAddWidgetModal = useCallback(() => {
setIsWidgetModalOpen(true);
}, []);
@ -212,7 +221,7 @@ function CustomizeMyData({
);
}
const Widget = CustomizePageClassBase.getWidgetsFromKey(widgetConfig.i);
const Widget = customizePageClassBase.getWidgetsFromKey(widgetConfig.i);
return (
<Widget
@ -222,6 +231,7 @@ function CustomizeMyData({
followedDataCount={followedDataCount}
handleRemoveWidget={handleRemoveWidget}
isLoadingOwnedData={isLoadingOwnedData}
selectedGridSize={widgetConfig.w}
widgetKey={widgetConfig.i}
/>
);
@ -315,7 +325,7 @@ function CustomizeMyData({
const handleReset = useCallback(() => {
setLayout([
...LANDING_PAGE_LAYOUT,
...customizePageClassBase.landingPageDefaultLayout,
{
h: 2,
i: LandingPageWidgetKeys.EMPTY_WIDGET_PLACEHOLDER,
@ -326,6 +336,7 @@ function CustomizeMyData({
},
]);
setResetRightPanelLayout(true);
setIsResetModalOpen(false);
}, []);
useEffect(() => {
@ -363,8 +374,8 @@ function CustomizeMyData({
<Button size="small" onClick={handleCancel}>
{t('label.cancel')}
</Button>
<Button size="small" onClick={handleReset}>
{t('label.reset-default-layout')}
<Button size="small" onClick={handleOpenResetModal}>
{t('label.reset')}
</Button>
<Button size="small" type="primary" onClick={handleSave}>
{t('label.save')}
@ -380,8 +391,11 @@ function CustomizeMyData({
cols={{ lg: 4, md: 4, sm: 4, xs: 4, xxs: 4 }}
draggableHandle=".drag-widget-icon"
isResizable={false}
margin={[LANDING_PAGE_WIDGET_MARGIN, LANDING_PAGE_WIDGET_MARGIN]}
rowHeight={LANDING_PAGE_ROW_HEIGHT}
margin={[
customizePageClassBase.landingPageWidgetMargin,
customizePageClassBase.landingPageWidgetMargin,
]}
rowHeight={customizePageClassBase.landingPageRowHeight}
style={{
backgroundImage: `url(${gridBgImg})`,
}}
@ -393,11 +407,23 @@ function CustomizeMyData({
addedWidgetsList={addedWidgetsList}
handleAddWidget={handleAddWidget}
handleCloseAddWidgetModal={handleCloseAddWidgetModal}
maxGridSizeSupport={LANDING_PAGE_MAX_GRID_SIZE}
maxGridSizeSupport={customizePageClassBase.landingPageMaxGridSize}
open={isWidgetModalOpen}
placeholderWidgetKey={placeholderWidgetKey}
/>
)}
{isResetModalOpen && (
<Modal
centered
cancelText={t('label.no')}
okText={t('label.yes')}
open={isResetModalOpen}
title={t('label.reset-default-layout')}
onCancel={handleCloseResetModal}
onOk={handleReset}>
{t('message.reset-layout-confirmation')}
</Modal>
)}
</ActivityFeedProvider>
</Col>
</Row>

View File

@ -32,6 +32,7 @@ import {
} from '../../constants/constants';
import { KPI_WIDGET_GRAPH_COLORS } from '../../constants/DataInsight.constants';
import { DATA_INSIGHT_DOCS } from '../../constants/docs.constants';
import { WidgetWidths } from '../../enums/CustomizablePage.enum';
import { Kpi, KpiResult } from '../../generated/dataInsight/kpi/kpi';
import { UIKpiResult } from '../../interface/data-insight.interface';
import {
@ -88,6 +89,7 @@ const KPIWidget = ({
selectedDays = CHART_WIDGET_DAYS_DURATION,
handleRemoveWidget,
widgetKey,
selectedGridSize = WidgetWidths.medium,
}: KPIWidgetProps) => {
const { t } = useTranslation();
const [kpiList, setKpiList] = useState<Array<Kpi>>([]);
@ -187,6 +189,11 @@ const KPIWidget = ({
!isUndefined(handleRemoveWidget) && handleRemoveWidget(widgetKey);
}, [widgetKey]);
const isWidgetSizeMedium = useMemo(
() => selectedGridSize === WidgetWidths.medium,
[selectedGridSize]
);
useEffect(() => {
fetchKpiList().catch(() => {
// catch handled in parent function
@ -211,34 +218,38 @@ const KPIWidget = ({
data-testid="kpi-card"
id="kpi-charts"
loading={isKPIListLoading || isLoading}>
<Row justify="end">
<Col>
{isEditView && (
<Space align="center">
<DragOutlined
className="drag-widget-icon cursor-pointer"
size={14}
/>
<CloseOutlined size={14} onClick={handleCloseClick} />
</Space>
)}
</Col>
</Row>
<Row align="middle" justify="space-between">
<Col>
<Typography.Text className="font-medium">
{t('label.kpi-title')}
</Typography.Text>
</Col>
{isEditView && (
<Space align="center">
<DragOutlined
className="drag-widget-icon cursor-pointer"
size={14}
/>
<CloseOutlined size={14} onClick={handleCloseClick} />
</Space>
)}
</Row>
{kpiList.length > 0 ? (
<Row>
<Row className="p-t-md">
{graphData.length ? (
<>
<Col span={14}>
<Col span={isWidgetSizeMedium ? 14 : 24}>
<ResponsiveContainer debounce={1} height={250} width="100%">
<LineChart
data={graphData}
margin={{
top: 10,
right: 50,
left: -20,
right: isWidgetSizeMedium ? 50 : 20,
left: -30,
bottom: 0,
}}>
<CartesianGrid
@ -258,16 +269,18 @@ const KPIWidget = ({
</LineChart>
</ResponsiveContainer>
</Col>
{!isUndefined(kpiLatestResults) && !isEmpty(kpiLatestResults) && (
<Col span={10}>
<KPILatestResultsV1
kpiLatestResultsRecord={kpiLatestResults}
/>
</Col>
)}
{!isUndefined(kpiLatestResults) &&
!isEmpty(kpiLatestResults) &&
isWidgetSizeMedium && (
<Col span={10}>
<KPILatestResultsV1
kpiLatestResultsRecord={kpiLatestResults}
/>
</Col>
)}
</>
) : (
<Col className="justify-center" span={24}>
<Col span={24}>
<EmptyPlaceholder />
</Col>
)}

View File

@ -37,6 +37,7 @@ const MyDataWidgetInternal = ({
const currentUserDetails = AppState.getCurrentUserDetails();
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState<EntityReference[]>([]);
const [totalOwnedAssetsCount, setTotalOwnedAssetsCount] = useState<number>(0);
const fetchMyDataAssets = async () => {
if (!currentUserDetails || !currentUserDetails.id) {
@ -54,7 +55,8 @@ const MyDataWidgetInternal = ({
includeData.includes(data.type as AssetsType)
);
setData(includedOwnsData.slice(0, 8));
setData(includedOwnsData.slice(0, 9));
setTotalOwnedAssetsCount(includedOwnsData.length);
}
} catch (err) {
setData([]);
@ -87,7 +89,7 @@ const MyDataWidgetInternal = ({
<span className="text-grey-muted font-normal text-xs">
{t('label.view-all')}{' '}
<span data-testid="my-data-total-count">
{`(${data.length})`}
{`(${totalOwnedAssetsCount})`}
</span>
</span>
</Link>

View File

@ -38,7 +38,7 @@ function AnnouncementsWidget({
}, [widgetKey]);
return (
<div className="bg-white h-full">
<div className="bg-white h-max-full overflow-y-scroll">
<Row justify="space-between">
<Col>
<Typography.Paragraph className="right-panel-label m-b-sm">

View File

@ -13,12 +13,6 @@
import { isEmpty, isUndefined, uniqBy } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Layout, Responsive, WidthProvider } from 'react-grid-layout';
import {
LANDING_PAGE_RIGHT_CONTAINER_MAX_GRID_SIZE,
LANDING_PAGE_ROW_HEIGHT,
LANDING_PAGE_WIDGET_MARGIN,
RIGHT_PANEL_LAYOUT,
} from '../../../constants/CustomizePage.constants';
import { SIZE } from '../../../enums/common.enum';
import { LandingPageWidgetKeys } from '../../../enums/CustomizablePage.enum';
import { Document } from '../../../generated/entity/docStore/document';
@ -28,7 +22,7 @@ import {
getLayoutUpdateHandler,
getRemoveWidgetHandler,
} from '../../../utils/CustomizableLandingPageUtils';
import { CustomizePageClassBase } from '../../../utils/CustomizePageClassBase';
import customizePageClassBase from '../../../utils/CustomizePageClassBase';
import AddWidgetModal from '../../CustomizableComponents/AddWidgetModal/AddWidgetModal';
import EmptyWidgetPlaceholder from '../../CustomizableComponents/EmptyWidgetPlaceholder/EmptyWidgetPlaceholder';
import './right-sidebar.less';
@ -86,12 +80,17 @@ const RightSidebar = ({
}, []);
const handleAddWidget = useCallback(
(newWidgetData: Document, placeholderWidgetKey: string) => {
(
newWidgetData: Document,
placeholderWidgetKey: string,
widgetSize: number
) => {
setLayout(
getAddWidgetHandler(
newWidgetData,
placeholderWidgetKey,
LANDING_PAGE_RIGHT_CONTAINER_MAX_GRID_SIZE
widgetSize,
customizePageClassBase.landingPageRightContainerMaxGridSize
)
);
setIsWidgetModalOpen(false);
@ -117,7 +116,7 @@ const RightSidebar = ({
);
}
const Widget = CustomizePageClassBase.getWidgetsFromKey(widgetConfig.i);
const Widget = customizePageClassBase.getWidgetsFromKey(widgetConfig.i);
return (
<Widget
@ -127,6 +126,7 @@ const RightSidebar = ({
handleRemoveWidget={handleRemoveWidget}
isEditView={isEditView}
isLoadingOwnedData={isLoadingOwnedData}
selectedGridSize={widgetConfig.w}
widgetKey={widgetConfig.i}
/>
);
@ -207,7 +207,7 @@ const RightSidebar = ({
useEffect(() => {
if (resetLayout && handleResetLayout) {
setLayout([
...RIGHT_PANEL_LAYOUT,
...customizePageClassBase.rightPanelDefaultLayout,
...(isEditView
? [
{
@ -230,11 +230,14 @@ const RightSidebar = ({
<ResponsiveGridLayout
breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
cols={{ lg: 1, md: 1, sm: 1, xs: 1, xxs: 1 }}
containerPadding={[0, LANDING_PAGE_WIDGET_MARGIN]}
containerPadding={[0, customizePageClassBase.landingPageWidgetMargin]}
draggableHandle=".drag-widget-icon"
isResizable={false}
margin={[LANDING_PAGE_WIDGET_MARGIN, LANDING_PAGE_WIDGET_MARGIN]}
rowHeight={LANDING_PAGE_ROW_HEIGHT}
margin={[
customizePageClassBase.landingPageWidgetMargin,
customizePageClassBase.landingPageWidgetMargin,
]}
rowHeight={customizePageClassBase.landingPageRowHeight}
onLayoutChange={handleLayoutUpdate}>
{widgets}
</ResponsiveGridLayout>
@ -243,7 +246,9 @@ const RightSidebar = ({
addedWidgetsList={addedWidgetsList}
handleAddWidget={handleAddWidget}
handleCloseAddWidgetModal={handleCloseAddWidgetModal}
maxGridSizeSupport={LANDING_PAGE_RIGHT_CONTAINER_MAX_GRID_SIZE}
maxGridSizeSupport={
customizePageClassBase.landingPageRightContainerMaxGridSize
}
open={isWidgetModalOpen}
placeholderWidgetKey={placeholderWidgetKey}
/>

View File

@ -11,9 +11,6 @@
* limitations under the License.
*/
.announcement-container-list {
max-height: 360px;
overflow-y: auto;
overflow-x: hidden;
.feed-card-body {
padding: 0;
}

View File

@ -33,6 +33,7 @@ import {
} from 'recharts';
import { CHART_WIDGET_DAYS_DURATION } from '../../constants/constants';
import { TOTAL_ENTITY_CHART_COLOR } from '../../constants/DataInsight.constants';
import { WidgetWidths } from '../../enums/CustomizablePage.enum';
import { DataReportIndex } from '../../generated/dataInsight/dataInsightChart';
import {
DataInsightChartResult,
@ -57,6 +58,7 @@ const TotalDataAssetsWidget = ({
selectedDays = CHART_WIDGET_DAYS_DURATION,
handleRemoveWidget,
widgetKey,
selectedGridSize,
}: TotalDataAssetsWidgetProps) => {
const [totalEntitiesByType, setTotalEntitiesByType] =
useState<DataInsightChartResult>();
@ -96,6 +98,11 @@ const TotalDataAssetsWidget = ({
!isUndefined(handleRemoveWidget) && handleRemoveWidget(widgetKey);
}, [widgetKey]);
const isWidgetSizeLarge = useMemo(
() => selectedGridSize === WidgetWidths.large,
[selectedGridSize]
);
useEffect(() => {
fetchTotalEntitiesByType();
}, [selectedDays]);
@ -121,18 +128,18 @@ const TotalDataAssetsWidget = ({
)}
{data.length ? (
<Row>
<Col span={14}>
<Col span={isWidgetSizeLarge ? 14 : 24}>
<Typography.Text className="font-medium">
{t('label.data-insight-total-entity-summary')}
</Typography.Text>
<div className="p-t-lg">
<div className="p-t-md">
<ResponsiveContainer height={250} width="100%">
<AreaChart
data={data}
margin={{
top: 10,
right: 50,
left: -20,
right: isWidgetSizeLarge ? 50 : 20,
left: -30,
bottom: 0,
}}
syncId="anyId">
@ -152,15 +159,17 @@ const TotalDataAssetsWidget = ({
</ResponsiveContainer>
</div>
</Col>
<Col span={10}>
<TotalEntityInsightSummary
entities={entities}
latestData={latestData}
relativePercentage={relativePercentage}
selectedDays={selectedDays}
total={total}
/>
</Col>
{isWidgetSizeLarge && (
<Col span={10}>
<TotalEntityInsightSummary
entities={entities}
latestData={latestData}
relativePercentage={relativePercentage}
selectedDays={selectedDays}
total={total}
/>
</Col>
)}
</Row>
) : (
<Row>

View File

@ -16,7 +16,6 @@ import { isUndefined } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
import AppState from '../../../AppState';
import ActivityFeedListV1 from '../../../components/ActivityFeed/ActivityFeedList/ActivityFeedListV1.component';
import { useActivityFeedProvider } from '../../../components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
import { ActivityFeedTabs } from '../../../components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface';
@ -32,6 +31,7 @@ import { WidgetCommonProps } from '../../../pages/CustomizablePage/CustomizableP
import { getFeedsWithFilter } from '../../../rest/feedsAPI';
import { getCountBadge, getEntityDetailLink } from '../../../utils/CommonUtils';
import { showErrorToast } from '../../../utils/ToastUtils';
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
import FeedsFilterPopover from '../../common/FeedsFilterPopover/FeedsFilterPopover.component';
import './feeds-widget.less';
@ -43,18 +43,16 @@ const FeedsWidget = ({
const { t } = useTranslation();
const history = useHistory();
const { isTourOpen } = useTourProvider();
const { currentUser } = useAuthContext();
const [activeTab, setActiveTab] = useState<ActivityFeedTabs>(
ActivityFeedTabs.ALL
);
const { loading, entityThread, entityPaging, getFeedData } =
useActivityFeedProvider();
const [taskCount, setTaskCount] = useState(0);
const currentUser = useMemo(
() => AppState.getCurrentUserDetails(),
[AppState.userDetails, AppState.nonSecureUserDetails]
);
const [defaultFilter, setDefaultFilter] = useState<FeedFilter>(
FeedFilter.OWNER_OR_FOLLOWS
currentUser?.isAdmin ? FeedFilter.ALL : FeedFilter.OWNER_OR_FOLLOWS
);
useEffect(() => {

View File

@ -1,107 +0,0 @@
/*
* Copyright 2023 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { LandingPageWidgetKeys } from '../enums/CustomizablePage.enum';
export const DEFAULT_WIDGET_HEIGHT = 3;
export const LANDING_PAGE_WIDGET_MARGIN = 16;
export const LANDING_PAGE_ROW_HEIGHT = 100;
export const LANDING_PAGE_RIGHT_CONTAINER_EDIT_HEIGHT = 16;
export const LANDING_PAGE_MAX_GRID_SIZE = 3;
export const LANDING_PAGE_RIGHT_CONTAINER_MAX_GRID_SIZE = 1;
export const LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS = {
activityFeed: 5,
rightSidebar: 11.5,
announcements: 3.9,
following: 2.4,
recentlyViewed: 2.1,
myData: 2.8,
kpi: 2.8,
totalDataAssets: 3.42,
};
export const RIGHT_PANEL_LAYOUT = [
{
h: LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.announcements,
i: LandingPageWidgetKeys.ANNOUNCEMENTS,
w: 1,
x: 0,
y: 0,
static: false,
},
{
h: LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.following,
i: LandingPageWidgetKeys.FOLLOWING,
w: 1,
x: 0,
y: 1.5,
static: false,
},
{
h: LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.recentlyViewed,
i: LandingPageWidgetKeys.RECENTLY_VIEWED,
w: 1,
x: 0,
y: 3,
static: false,
},
];
export const LANDING_PAGE_LAYOUT = [
{
h: LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.activityFeed,
i: LandingPageWidgetKeys.ACTIVITY_FEED,
w: 3,
x: 0,
y: 0,
static: false,
},
{
h: LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.rightSidebar,
i: LandingPageWidgetKeys.RIGHT_PANEL,
w: 1,
x: 3,
y: 0,
data: {
page: {
layout: RIGHT_PANEL_LAYOUT,
},
},
static: true,
},
{
h: LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.myData,
i: LandingPageWidgetKeys.MY_DATA,
w: 1,
x: 0,
y: 6,
static: false,
},
{
h: LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.kpi,
i: LandingPageWidgetKeys.KPI,
w: 2,
x: 1,
y: 6,
static: false,
},
{
h: LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.totalDataAssets,
i: LandingPageWidgetKeys.TOTAL_DATA_ASSETS,
w: 3,
x: 0,
y: 9.1,
static: false,
},
];

View File

@ -1467,6 +1467,7 @@
"rename-entity": "Benennen Sie den Namen und die Anzeigebezeichnung für das {{entity}} um.",
"request-description": "Beschreibung der Anfrage",
"request-update-description": "Aktualisierung der Anfragebeschreibung",
"reset-layout-confirmation": "Are you sure you want to apply the \"Default Layout\"?",
"reset-link-has-been-sent": "Der Zurücksetzungslink wurde an Ihre E-Mail gesendet",
"restore-action-description": "Durch das Wiederherstellen dieses {{entityType}} werden seine Metadaten in OpenMetadata wiederhergestellt.",
"restore-deleted-team": "Das Wiederherstellen des Teams fügt alle Metadaten wieder zu OpenMetadata hinzu.",

View File

@ -1467,6 +1467,7 @@
"rename-entity": "Rename the Name and Display Name for the {{entity}}.",
"request-description": "Request description",
"request-update-description": "Request update description",
"reset-layout-confirmation": "Are you sure you want to apply the \"Default Layout\"?",
"reset-link-has-been-sent": "Reset link has been sent to your email",
"restore-action-description": "Restoring this {{entityType}} will restore its metadata in OpenMetadata.",
"restore-deleted-team": " Restoring the Team will add all the metadata back to OpenMetadata",

View File

@ -1467,6 +1467,7 @@
"rename-entity": "Renombrar el nombre y nombre visualizado para el {{entity}}.",
"request-description": "Descripción de la solicitud",
"request-update-description": "Descripción de la actualización de la solicitud",
"reset-layout-confirmation": "Are you sure you want to apply the \"Default Layout\"?",
"reset-link-has-been-sent": "Se ha enviado un enlace de restablecimiento a tu correo electrónico",
"restore-action-description": "Restaurar este {{entityType}} restaurará sus metadatos en OpenMetadata.",
"restore-deleted-team": "Restaurar el equipo agregará todos los metadatos de nuevo a OpenMetadata",

View File

@ -1467,6 +1467,7 @@
"rename-entity": "Renommer le nom et le nom d'affichage pour {{entity}}.",
"request-description": "Demander une description",
"request-update-description": "Mettre à jour la demande de description",
"reset-layout-confirmation": "Are you sure you want to apply the \"Default Layout\"?",
"reset-link-has-been-sent": "Lien de réinitialisation a été envoyé à votre adresse e-mail.",
"restore-action-description": "Restaurer cette {{entityType}} restaurera les métadonnées dans OpenMetadata.",
"restore-deleted-team": " Restaurer cette Equipe ajoutera toutes les métadonnées dans OpenMetadata",

View File

@ -1467,6 +1467,7 @@
"rename-entity": "Rename the Name and Display Name for the {{entity}}.",
"request-description": "Request description",
"request-update-description": "Request update description",
"reset-layout-confirmation": "Are you sure you want to apply the \"Default Layout\"?",
"reset-link-has-been-sent": "パスワードリセット用のリンクがあなたのメールアドレスに送信されました",
"restore-action-description": "この{{entityType}}をリストアすると、OpenMetadataのメタデータがリストアされます。",
"restore-deleted-team": "チームをリストアすると全てのメタデータがOpenMetadataに戻されます。",

View File

@ -1467,6 +1467,7 @@
"rename-entity": "Rename the Name and Display Name for the {{entity}}.",
"request-description": "Descrição da solicitação",
"request-update-description": "Atualizar descrição da solicitação",
"reset-layout-confirmation": "Are you sure you want to apply the \"Default Layout\"?",
"reset-link-has-been-sent": "O link de redefinição foi enviado para o seu e-mail",
"restore-action-description": "Restaurar esta {{entityType}} irá restaurar seus metadados no OpenMetadata.",
"restore-deleted-team": "Restaurar a equipe irá adicionar todos os metadados de volta ao OpenMetadata",

View File

@ -1467,6 +1467,7 @@
"rename-entity": "Измените имя и отображаемое имя для {{entity}}.",
"request-description": "Запросить описание",
"request-update-description": "Запросить обновление описания",
"reset-layout-confirmation": "Are you sure you want to apply the \"Default Layout\"?",
"reset-link-has-been-sent": "Ссылка для сброса отправлена на вашу электронную почту",
"restore-action-description": "Восстановление этого {{entityType}} восстановит его метаданные в OpenMetadata.",
"restore-deleted-team": "Восстановление команды добавит все метаданные обратно в OpenMetadata.",

View File

@ -1467,6 +1467,7 @@
"rename-entity": "修改{{entity}}的名称和显示名",
"request-description": "请求详细描述",
"request-update-description": "请求更新描述",
"reset-layout-confirmation": "Are you sure you want to apply the \"Default Layout\"?",
"reset-link-has-been-sent": "重置链接已发送到您的电子邮箱",
"restore-action-description": "还原此{{entityType}}将在 OpenMetadata 中还原其元数据",
"restore-deleted-team": "还原团队将会把所有元数据添加回 OpenMetadata",

View File

@ -23,6 +23,7 @@ export interface WidgetConfig
}
export interface WidgetCommonProps {
selectedGridSize?: number;
isEditView?: boolean;
widgetKey: string;
handleRemoveWidget?: (widgetKey: string) => void;

View File

@ -16,7 +16,6 @@ import React, { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import CustomizeMyData from '../../components/CustomizableComponents/CustomizeMyData/CustomizeMyData';
import Loader from '../../components/Loader/Loader';
import { LANDING_PAGE_LAYOUT } from '../../constants/CustomizePage.constants';
import { ClientErrors } from '../../enums/axios.enum';
import { EntityType } from '../../enums/entity.enum';
import { Document } from '../../generated/entity/docStore/document';
@ -27,6 +26,7 @@ import {
updateDocument,
} from '../../rest/DocStoreAPI';
import { getFinalLandingPage } from '../../utils/CustomizableLandingPageUtils';
import customizePageClassBase from '../../utils/CustomizePageClassBase';
export const CustomizablePage = () => {
const { fqn, pageFqn } = useParams<{ fqn: string; pageFqn: PageType }>();
@ -57,7 +57,7 @@ export const CustomizablePage = () => {
entityType: EntityType.PAGE,
data: {
page: {
layout: LANDING_PAGE_LAYOUT,
layout: customizePageClassBase.landingPageDefaultLayout,
},
},
},

View File

@ -31,10 +31,6 @@ import Loader from '../../components/Loader/Loader';
import RightSidebar from '../../components/MyData/RightSidebar/RightSidebar.component';
import WelcomeScreen from '../../components/WelcomeScreen/WelcomeScreen.component';
import { LOGGED_IN_USER_STORAGE_KEY } from '../../constants/constants';
import {
LANDING_PAGE_LAYOUT,
LANDING_PAGE_WIDGET_MARGIN,
} from '../../constants/CustomizePage.constants';
import { LandingPageWidgetKeys } from '../../enums/CustomizablePage.enum';
import { AssetsType, EntityType } from '../../enums/entity.enum';
import { Thread } from '../../generated/entity/feed/thread';
@ -44,7 +40,7 @@ import { useAuth } from '../../hooks/authHooks';
import { getDocumentByFQN } from '../../rest/DocStoreAPI';
import { getActiveAnnouncement } from '../../rest/feedsAPI';
import { getUserById } from '../../rest/userAPI';
import { CustomizePageClassBase } from '../../utils/CustomizePageClassBase';
import customizePageClassBase from '../../utils/CustomizePageClassBase';
import { showErrorToast } from '../../utils/ToastUtils';
import { WidgetConfig } from '../CustomizablePage/CustomizablePage.interface';
import './my-data.less';
@ -86,10 +82,10 @@ const MyDataPageV1 = () => {
const pageData = await getDocumentByFQN(pageFQN);
setLayout(pageData.data.page.layout);
} else {
setLayout(LANDING_PAGE_LAYOUT);
setLayout(customizePageClassBase.landingPageDefaultLayout);
}
} catch {
setLayout(LANDING_PAGE_LAYOUT);
setLayout(customizePageClassBase.landingPageDefaultLayout);
} finally {
setIsLoading(false);
}
@ -173,7 +169,7 @@ const MyDataPageV1 = () => {
);
}
const Widget = CustomizePageClassBase.getWidgetsFromKey(widgetConfig.i);
const Widget = customizePageClassBase.getWidgetsFromKey(widgetConfig.i);
return (
<Widget
@ -181,6 +177,7 @@ const MyDataPageV1 = () => {
followedData={followedData ?? []}
followedDataCount={followedDataCount}
isLoadingOwnedData={isLoadingOwnedData}
selectedGridSize={widgetConfig.w}
widgetKey={widgetConfig.i}
/>
);
@ -255,7 +252,10 @@ const MyDataPageV1 = () => {
cols={{ lg: 4, md: 4, sm: 4, xs: 4, xxs: 4 }}
draggableHandle=".drag-widget-icon"
isResizable={false}
margin={[LANDING_PAGE_WIDGET_MARGIN, LANDING_PAGE_WIDGET_MARGIN]}
margin={[
customizePageClassBase.landingPageWidgetMargin,
customizePageClassBase.landingPageWidgetMargin,
]}
rowHeight={100}>
{widgets}
</ResponsiveGridLayout>

View File

@ -273,6 +273,9 @@
.h-full {
height: 100%;
}
.h-max-full {
max-height: 100%;
}
.h-auto {
height: auto;
}
@ -284,3 +287,11 @@
.max-width-md {
max-width: 768px;
}
.overflow-y-scroll {
overflow-y: scroll;
}
.overflow-x-scroll {
overflow-x: scroll;
}

View File

@ -21,30 +21,26 @@ import {
uniqueId,
} from 'lodash';
import { Layout } from 'react-grid-layout';
import {
DEFAULT_WIDGET_HEIGHT,
LANDING_PAGE_RIGHT_CONTAINER_EDIT_HEIGHT,
LANDING_PAGE_ROW_HEIGHT,
LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS,
LANDING_PAGE_WIDGET_MARGIN,
} from '../constants/CustomizePage.constants';
import {
LandingPageWidgetKeys,
WidgetWidths,
} from '../enums/CustomizablePage.enum';
import { Document } from '../generated/entity/docStore/document';
import { WidgetConfig } from '../pages/CustomizablePage/CustomizablePage.interface';
import customizePageClassBase from './CustomizePageClassBase';
export const getAddWidgetHandler =
(
newWidgetData: Document,
placeholderWidgetKey: string,
widgetWidth: number,
maxGridSize: number
) =>
(currentLayout: Array<WidgetConfig>) => {
const widgetFQN = uniqueId(`${newWidgetData.fullyQualifiedName}-`);
const widgetWidth = getWidgetWidth(newWidgetData);
const widgetHeight = getWidgetHeight(newWidgetData.name);
const widgetHeight = customizePageClassBase.getWidgetHeight(
newWidgetData.name
);
// The widget with key "ExtraWidget.EmptyWidgetPlaceholder" will always remain in the bottom
// and is not meant to be replaced hence
@ -142,29 +138,6 @@ export const getWidgetWidth = (widget: Document) => {
return widgetSize as number;
};
export const getWidgetHeight = (widgetName: string) => {
switch (widgetName) {
case 'ActivityFeed':
return LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.activityFeed;
case 'RightSidebar':
return LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.rightSidebar;
case 'Announcements':
return LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.announcements;
case 'Following':
return LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.following;
case 'RecentlyViewed':
return LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.recentlyViewed;
case 'MyData':
return LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.myData;
case 'KPI':
return LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.kpi;
case 'TotalDataAssets':
return LANDING_PAGE_WIDGET_DEFAULT_HEIGHTS.totalDataAssets;
default:
return DEFAULT_WIDGET_HEIGHT;
}
};
const getAllWidgetsArray = (layout: WidgetConfig[]) => {
const widgetsArray: WidgetConfig[] = [];
@ -191,13 +164,15 @@ const getLayoutWithCalculatedRightPanelHeight = (
const floorHeightAndPosValue = floor(widgetHeightAndPos);
const heightOfWidget =
widgetHeightAndPos * LANDING_PAGE_ROW_HEIGHT +
(floorHeightAndPosValue + 1) * LANDING_PAGE_WIDGET_MARGIN;
widgetHeightAndPos * customizePageClassBase.landingPageRowHeight +
(floorHeightAndPosValue + 1) *
customizePageClassBase.landingPageWidgetMargin;
return {
h: round(
(heightOfWidget + LANDING_PAGE_WIDGET_MARGIN) /
(LANDING_PAGE_ROW_HEIGHT + LANDING_PAGE_WIDGET_MARGIN),
(heightOfWidget + customizePageClassBase.landingPageWidgetMargin) /
(customizePageClassBase.landingPageRowHeight +
customizePageClassBase.landingPageWidgetMargin),
2
),
height: heightOfWidget,
@ -211,7 +186,7 @@ const getLayoutWithCalculatedRightPanelHeight = (
? {
...widget,
h: increaseHeight
? LANDING_PAGE_RIGHT_CONTAINER_EDIT_HEIGHT
? customizePageClassBase.landingPageRightContainerEditHeight
: maxHeight?.h ?? widget.h,
}
: widget

View File

@ -30,10 +30,121 @@ import FollowingWidget, {
import RecentlyViewed from '../components/recently-viewed/RecentlyViewed';
import TotalDataAssetsWidget from '../components/TotalDataAssetsWidget/TotalDataAssetsWidget.component';
import FeedsWidget from '../components/Widgets/FeedsWidget/FeedsWidget.component';
import { LandingPageWidgetKeys } from '../enums/CustomizablePage.enum';
import { WidgetCommonProps } from '../pages/CustomizablePage/CustomizablePage.interface';
import {
LandingPageWidgetKeys,
WidgetWidths,
} from '../enums/CustomizablePage.enum';
import {
WidgetCommonProps,
WidgetConfig,
} from '../pages/CustomizablePage/CustomizablePage.interface';
class CustomizePageClassBase {
defaultWidgetHeight = 3;
landingPageWidgetMargin = 16;
landingPageRowHeight = 100;
landingPageRightContainerEditHeight = 16;
landingPageMaxGridSize = 3;
landingPageRightContainerMaxGridSize = 1;
landingPageWidgetDefaultHeights: Record<string, number> = {
activityFeed: 5,
rightSidebar: 11.5,
announcements: 3.1,
following: 2.4,
recentlyViewed: 2.1,
myData: 3.1,
kpi: 3.1,
totalAssets: 3.1,
};
rightPanelDefaultLayout: Array<WidgetConfig> = [
{
h: this.landingPageWidgetDefaultHeights.announcements,
i: LandingPageWidgetKeys.ANNOUNCEMENTS,
w: 1,
x: 0,
y: 0,
static: false,
},
{
h: this.landingPageWidgetDefaultHeights.following,
i: LandingPageWidgetKeys.FOLLOWING,
w: 1,
x: 0,
y: 1.5,
static: false,
},
{
h: this.landingPageWidgetDefaultHeights.recentlyViewed,
i: LandingPageWidgetKeys.RECENTLY_VIEWED,
w: 1,
x: 0,
y: 3,
static: false,
},
];
landingPageDefaultLayout: Array<WidgetConfig> = [
{
h: this.landingPageWidgetDefaultHeights.activityFeed,
i: LandingPageWidgetKeys.ACTIVITY_FEED,
w: 3,
x: 0,
y: 0,
static: false,
},
{
h: this.landingPageWidgetDefaultHeights.rightSidebar,
i: LandingPageWidgetKeys.RIGHT_PANEL,
w: 1,
x: 3,
y: 0,
data: {
page: {
layout: this.rightPanelDefaultLayout,
},
},
static: true,
},
{
h: this.landingPageWidgetDefaultHeights.myData,
i: LandingPageWidgetKeys.MY_DATA,
w: 1,
x: 0,
y: 6,
static: false,
},
{
h: this.landingPageWidgetDefaultHeights.kpi,
i: LandingPageWidgetKeys.KPI,
w: 2,
x: 1,
y: 6,
static: false,
},
{
h: this.landingPageWidgetDefaultHeights.totalAssets,
i: LandingPageWidgetKeys.TOTAL_DATA_ASSETS,
w: 3,
x: 0,
y: 9.1,
static: false,
},
];
protected updateRightPanelDefaultLayout(layout: Array<WidgetConfig>) {
this.rightPanelDefaultLayout = layout;
}
protected updateLandingPageDefaultLayout(layout: Array<WidgetConfig>) {
this.landingPageDefaultLayout = layout;
}
protected updateLandingPageWidgetDefaultHeights(obj: Record<string, number>) {
this.landingPageWidgetDefaultHeights = obj;
}
export class CustomizePageClassBase {
/**
*
* @param string widgetKey
@ -49,11 +160,9 @@ export class CustomizePageClassBase {
}
>
*/
static getWidgetsFromKey = (
public getWidgetsFromKey(
widgetKey: string
): FC<
WidgetCommonProps & AnnouncementsWidgetProps & FollowingWidgetProps
> => {
): FC<WidgetCommonProps & AnnouncementsWidgetProps & FollowingWidgetProps> {
if (widgetKey.startsWith(LandingPageWidgetKeys.ACTIVITY_FEED)) {
return FeedsWidget;
}
@ -77,9 +186,9 @@ export class CustomizePageClassBase {
}
return (() => null) as React.FC;
};
}
static getWidgetImageFromKey = (widgetKey: string): string => {
public getWidgetImageFromKey(widgetKey: string, size?: number): string {
switch (widgetKey) {
case LandingPageWidgetKeys.ACTIVITY_FEED: {
return ActivityFeedImg;
@ -88,9 +197,17 @@ export class CustomizePageClassBase {
return MyDataImg;
}
case LandingPageWidgetKeys.KPI: {
if (size === WidgetWidths.small) {
return '';
}
return KPIImg;
}
case LandingPageWidgetKeys.TOTAL_DATA_ASSETS: {
if (size === WidgetWidths.medium) {
return '';
}
return TotalAssetsImg;
}
case LandingPageWidgetKeys.ANNOUNCEMENTS: {
@ -106,5 +223,33 @@ export class CustomizePageClassBase {
return '';
}
}
};
}
public getWidgetHeight(widgetName: string) {
switch (widgetName) {
case 'ActivityFeed':
return this.landingPageWidgetDefaultHeights.activityFeed;
case 'RightSidebar':
return this.landingPageWidgetDefaultHeights.rightSidebar;
case 'Announcements':
return this.landingPageWidgetDefaultHeights.announcements;
case 'Following':
return this.landingPageWidgetDefaultHeights.following;
case 'RecentlyViewed':
return this.landingPageWidgetDefaultHeights.recentlyViewed;
case 'MyData':
return this.landingPageWidgetDefaultHeights.myData;
case 'KPI':
return this.landingPageWidgetDefaultHeights.kpi;
case 'TotalAssets':
return this.landingPageWidgetDefaultHeights.totalAssets;
default:
return this.defaultWidgetHeight;
}
}
}
const customizePageClassBase = new CustomizePageClassBase();
export default customizePageClassBase;
export { CustomizePageClassBase };

View File

@ -328,18 +328,18 @@ export const getGlobalSettingsMenuWithPermission = (
category: i18next.t('label.open-metadata'),
key: 'openMetadata',
items: [
{
label: i18next.t('label.email'),
isProtected: Boolean(isAdminUser),
key: 'openMetadata.email',
icon: <EmailSettingsIcon className="w-4 side-panel-icons" />,
},
{
label: i18next.t('label.customize-landing-page'),
isProtected: Boolean(isAdminUser),
key: 'openMetadata.customizeLandingPage',
icon: <CustomDashboardLogoIcon className="w-4 side-panel-icons" />,
},
{
label: i18next.t('label.email'),
isProtected: Boolean(isAdminUser),
key: 'openMetadata.email',
icon: <EmailSettingsIcon className="w-4 side-panel-icons" />,
},
{
label: i18next.t('label.custom-logo'),
isProtected: Boolean(isAdminUser),