mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-11-04 04:29:13 +00:00 
			
		
		
		
	Feat: Revamping Landing page for new design (#1541)
* Feat: Revamping Landing page for new design * Added Filter support for feeds * Added Feeds card component. * Removed Unwanted codes * Added API support for feeddata * Adding types * Added support for view all following and owned data. * Adding day seperator. * Added support to view data owned by team. * Adding support for feedFilters * Moved sorting from feed component to mydada component. * Adding testid * Added License to new file * Adding utils to get rekative date and time. * Adding getOwnerIds Util * Adding No data placholder. Co-authored-by: Sachin-chaurasiya <sachinchaurasiyachotey87@gmail.com>
This commit is contained in:
		
							parent
							
								
									64386b035e
								
							
						
					
					
						commit
						689e5beaea
					
				@ -1,5 +1,6 @@
 | 
				
			|||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="512" height="512" x="0" y="0" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512" xml:space="preserve">
 | 
					<svg width="400" height="399" viewBox="0 0 400 399" fill="none" xmlns="http://www.w3.org/2000/svg">
 | 
				
			||||||
<path d="M481.429,332.892c-26.337-26.357-62.882-37.523-109.815-24.945L204.256,140.419l2.212-8.364    c9.639-36.166-0.776-75.041-27.172-101.437C152.42,3.721,114.212-6.148,78.077,3.778c-5.153,1.415-9.164,5.464-10.529,10.631    c-1.365,5.167,0.132,10.659,3.909,14.438l40.297,40.297c11.781,11.81,11.666,30.724,0.029,42.392    c-11.545,11.576-30.951,11.558-42.45,0.029L29.028,71.257c-3.779-3.781-9.287-5.264-14.454-3.891    c-5.168,1.372-9.202,5.393-10.612,10.551c-9.781,35.738-0.159,74.183,26.846,101.188c26.326,26.345,62.825,37.551,109.786,24.946    l167.371,167.528c-12.49,46.919-1.716,83.11,24.975,109.801c26.91,26.93,65.136,36.726,101.192,26.833    c5.154-1.414,9.166-5.464,10.532-10.631c1.366-5.167-0.13-10.66-3.909-14.44l-40.288-40.288    c-11.781-11.81-11.666-30.726-0.029-42.392c11.689-11.629,31.052-11.444,42.45-0.015l40.308,40.297    c3.779,3.779,9.287,5.262,14.453,3.889c5.167-1.373,9.201-5.392,10.611-10.549C518.041,398.352,508.421,359.897,481.429,332.892z" fill="#6b7280" data-original="#000000" style=""></path>
 | 
					<path d="M400 190.5V150.5H354C318 150.5 285.333 203.167 274 229.5L240.5 211L254.5 309.5L342.5 270L308.5 249.5C308.5 249.5 328 190.5 364 190.5H400Z" fill="#6b7280"/>
 | 
				
			||||||
<path d="M160.551,266.584L17.559,409.594c-23.401,23.401-23.401,61.455,0,84.855c23.401,23.401,61.455,23.401,84.855,0    l142.989-143.006L160.551,266.584z M88.322,447.898c-5.86,5.86-15.35,5.86-21.21,0c-5.859-5.859-5.859-15.351,0-21.21    l90.98-90.997c5.859-5.859,15.352-5.859,21.21,0c5.859,5.859,5.859,15.351,0,21.21L88.322,447.898z" fill="#6b7280" data-original="#000000" style=""></path>
 | 
					<path d="M0.5 190.5V150.5H46.5C82.5 150.5 115.167 203.167 126.5 229.5L160 211L146 309.5L58 270L92 249.5C92 249.5 72.5 190.5 36.5 190.5H0.5Z" fill="#6b7280"/>
 | 
				
			||||||
<path d="M507.596,30.253L481.737,4.394c-4.867-4.867-12.42-5.797-18.322-2.258l-79.547,47.723    c-8.37,5.021-9.791,16.568-2.891,23.469l6.332,6.33l-100.98,100.567l42.435,42.435l100.98-100.567l8.919,8.921    c6.901,6.899,18.449,5.479,23.469-2.891l47.723-79.547C513.393,42.673,512.463,35.12,507.596,30.253z" fill="#6b7280" data-original="#000000" style=""></path>
 | 
					<path d="M219 0H179.5V109H129.5L200.5 192.5L268 109H219V0Z" fill="#6b7280"/>
 | 
				
			||||||
</svg>
 | 
					<path fill-rule="evenodd" clip-rule="evenodd" d="M399 310V381.807C399 391.302 391.292 399 381.784 399H18.2163C8.70799 399 1 391.302 1 381.807V310.399H39.2886V361H361.5V310H399Z" fill="#6b7280"/>
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 702 B  | 
@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Copyright 2021 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 { FormatedTableData } from 'Models';
 | 
				
			||||||
 | 
					import React, { FunctionComponent } from 'react';
 | 
				
			||||||
 | 
					import { Link } from 'react-router-dom';
 | 
				
			||||||
 | 
					import { getEntityIcon, getEntityLink } from '../../utils/TableUtils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Prop {
 | 
				
			||||||
 | 
					  entityList: Array<FormatedTableData>;
 | 
				
			||||||
 | 
					  headerText: string | JSX.Element;
 | 
				
			||||||
 | 
					  noDataPlaceholder: JSX.Element;
 | 
				
			||||||
 | 
					  testIDText: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const EntityList: FunctionComponent<Prop> = ({
 | 
				
			||||||
 | 
					  entityList = [],
 | 
				
			||||||
 | 
					  headerText,
 | 
				
			||||||
 | 
					  noDataPlaceholder,
 | 
				
			||||||
 | 
					  testIDText,
 | 
				
			||||||
 | 
					}: Prop) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <h6 className="tw-heading tw-mb-3" data-testid="filter-heading">
 | 
				
			||||||
 | 
					        {headerText}
 | 
				
			||||||
 | 
					      </h6>
 | 
				
			||||||
 | 
					      {entityList.length
 | 
				
			||||||
 | 
					        ? entityList.map((item, index) => {
 | 
				
			||||||
 | 
					            return (
 | 
				
			||||||
 | 
					              <div
 | 
				
			||||||
 | 
					                className="tw-flex tw-items-center tw-justify-between tw-mb-2"
 | 
				
			||||||
 | 
					                data-testid={`${testIDText}-${item.name}`}
 | 
				
			||||||
 | 
					                key={index}>
 | 
				
			||||||
 | 
					                <div className="tw-flex">
 | 
				
			||||||
 | 
					                  {getEntityIcon(item.index)}
 | 
				
			||||||
 | 
					                  <Link
 | 
				
			||||||
 | 
					                    className="tw-font-medium tw-pl-2"
 | 
				
			||||||
 | 
					                    to={getEntityLink(item.index, item.fullyQualifiedName)}>
 | 
				
			||||||
 | 
					                    <button className="tw-text-grey-body hover:tw-text-primary-hover hover:tw-underline">
 | 
				
			||||||
 | 
					                      {item.name}
 | 
				
			||||||
 | 
					                    </button>
 | 
				
			||||||
 | 
					                  </Link>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        : noDataPlaceholder}
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default EntityList;
 | 
				
			||||||
@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Copyright 2021 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 { isNil } from 'lodash';
 | 
				
			||||||
 | 
					import { observer } from 'mobx-react';
 | 
				
			||||||
 | 
					import { EntityCounts } from 'Models';
 | 
				
			||||||
 | 
					import React, { FunctionComponent, useEffect, useState } from 'react';
 | 
				
			||||||
 | 
					import { Link } from 'react-router-dom';
 | 
				
			||||||
 | 
					import AppState from '../../AppState';
 | 
				
			||||||
 | 
					import { getCountBadge } from '../../utils/CommonUtils';
 | 
				
			||||||
 | 
					import SVGIcons, { Icons } from '../../utils/SvgUtils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = {
 | 
				
			||||||
 | 
					  countServices: number;
 | 
				
			||||||
 | 
					  ingestionCount: number;
 | 
				
			||||||
 | 
					  entityCounts: EntityCounts;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					type Summary = {
 | 
				
			||||||
 | 
					  icon: string;
 | 
				
			||||||
 | 
					  data: string;
 | 
				
			||||||
 | 
					  count?: number;
 | 
				
			||||||
 | 
					  link?: string;
 | 
				
			||||||
 | 
					  dataTestId?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MyAssetStats: FunctionComponent<Props> = ({
 | 
				
			||||||
 | 
					  countServices,
 | 
				
			||||||
 | 
					  entityCounts,
 | 
				
			||||||
 | 
					  ingestionCount,
 | 
				
			||||||
 | 
					}: Props) => {
 | 
				
			||||||
 | 
					  const { users, userTeams } = AppState;
 | 
				
			||||||
 | 
					  const [dataSummary, setdataSummary] = useState<Record<string, Summary>>({});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getSummarydata = () => {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      tables: {
 | 
				
			||||||
 | 
					        icon: Icons.TABLE_GREY,
 | 
				
			||||||
 | 
					        data: 'Tables',
 | 
				
			||||||
 | 
					        count: entityCounts.tableCount,
 | 
				
			||||||
 | 
					        link: `/explore/tables`,
 | 
				
			||||||
 | 
					        dataTestId: 'tables',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      topics: {
 | 
				
			||||||
 | 
					        icon: Icons.TOPIC_GREY,
 | 
				
			||||||
 | 
					        data: 'Topics',
 | 
				
			||||||
 | 
					        count: entityCounts.topicCount,
 | 
				
			||||||
 | 
					        link: `/explore/topics`,
 | 
				
			||||||
 | 
					        dataTestId: 'topics',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      dashboards: {
 | 
				
			||||||
 | 
					        icon: Icons.DASHBOARD_GREY,
 | 
				
			||||||
 | 
					        data: 'Dashboards',
 | 
				
			||||||
 | 
					        count: entityCounts.dashboardCount,
 | 
				
			||||||
 | 
					        link: `/explore/dashboards`,
 | 
				
			||||||
 | 
					        dataTestId: 'dashboards',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      pipelines: {
 | 
				
			||||||
 | 
					        icon: Icons.PIPELINE_GREY,
 | 
				
			||||||
 | 
					        data: 'Pipelines',
 | 
				
			||||||
 | 
					        count: entityCounts.pipelineCount,
 | 
				
			||||||
 | 
					        link: `/explore/pipelines`,
 | 
				
			||||||
 | 
					        dataTestId: 'pipelines',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      service: {
 | 
				
			||||||
 | 
					        icon: Icons.SERVICE,
 | 
				
			||||||
 | 
					        data: 'Services',
 | 
				
			||||||
 | 
					        count: countServices,
 | 
				
			||||||
 | 
					        link: `/services`,
 | 
				
			||||||
 | 
					        dataTestId: 'service',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      ingestion: {
 | 
				
			||||||
 | 
					        icon: Icons.INGESTION,
 | 
				
			||||||
 | 
					        data: 'Ingestion',
 | 
				
			||||||
 | 
					        count: ingestionCount,
 | 
				
			||||||
 | 
					        link: `/ingestion`,
 | 
				
			||||||
 | 
					        dataTestId: 'ingestion',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      user: {
 | 
				
			||||||
 | 
					        icon: Icons.USERS,
 | 
				
			||||||
 | 
					        data: 'Users',
 | 
				
			||||||
 | 
					        count: users.length,
 | 
				
			||||||
 | 
					        link: `/teams`,
 | 
				
			||||||
 | 
					        dataTestId: 'user',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      terms: {
 | 
				
			||||||
 | 
					        icon: Icons.TERMS,
 | 
				
			||||||
 | 
					        data: 'Teams',
 | 
				
			||||||
 | 
					        count: userTeams.length,
 | 
				
			||||||
 | 
					        link: `/teams`,
 | 
				
			||||||
 | 
					        dataTestId: 'terms',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    setdataSummary(getSummarydata());
 | 
				
			||||||
 | 
					  }, [userTeams, users, countServices]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="tw-mb-3" data-testid="data-summary-container">
 | 
				
			||||||
 | 
					      {Object.values(dataSummary).map((data, index) => (
 | 
				
			||||||
 | 
					        <div
 | 
				
			||||||
 | 
					          className="tw-flex tw-items-center tw-justify-between tw-mb-2"
 | 
				
			||||||
 | 
					          key={index}>
 | 
				
			||||||
 | 
					          <div className="tw-flex">
 | 
				
			||||||
 | 
					            <SVGIcons alt="icon" className="tw-h-4 tw-w-4" icon={data.icon} />
 | 
				
			||||||
 | 
					            {data.link ? (
 | 
				
			||||||
 | 
					              <Link
 | 
				
			||||||
 | 
					                className="tw-font-medium tw-pl-2"
 | 
				
			||||||
 | 
					                data-testid={data.dataTestId}
 | 
				
			||||||
 | 
					                to={data.link}>
 | 
				
			||||||
 | 
					                <button className="tw-text-grey-body hover:tw-text-primary-hover hover:tw-underline">
 | 
				
			||||||
 | 
					                  {data.data}
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					              </Link>
 | 
				
			||||||
 | 
					            ) : (
 | 
				
			||||||
 | 
					              <p className="tw-font-medium tw-pl-2">{data.data}</p>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          {!isNil(data.count) && getCountBadge(data.count, '', false)}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      ))}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default observer(MyAssetStats);
 | 
				
			||||||
@ -0,0 +1,142 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Copyright 2021 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 { getByTestId, getByText, render } from '@testing-library/react';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { MemoryRouter } from 'react-router';
 | 
				
			||||||
 | 
					import MyAssetStats from './MyAssetStats.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('Test MyDataHeader Component', () => {
 | 
				
			||||||
 | 
					  it('Component should render', () => {
 | 
				
			||||||
 | 
					    const { container } = render(
 | 
				
			||||||
 | 
					      <MyAssetStats
 | 
				
			||||||
 | 
					        countServices={193}
 | 
				
			||||||
 | 
					        entityCounts={{
 | 
				
			||||||
 | 
					          tableCount: 40,
 | 
				
			||||||
 | 
					          topicCount: 13,
 | 
				
			||||||
 | 
					          dashboardCount: 10,
 | 
				
			||||||
 | 
					          pipelineCount: 3,
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        ingestionCount={0}
 | 
				
			||||||
 | 
					      />,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        wrapper: MemoryRouter,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const myDataHeader = getByTestId(container, 'data-header-container');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(myDataHeader).toBeInTheDocument();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('Should have main title', () => {
 | 
				
			||||||
 | 
					    const { container } = render(
 | 
				
			||||||
 | 
					      <MyAssetStats
 | 
				
			||||||
 | 
					        countServices={193}
 | 
				
			||||||
 | 
					        entityCounts={{
 | 
				
			||||||
 | 
					          tableCount: 40,
 | 
				
			||||||
 | 
					          topicCount: 13,
 | 
				
			||||||
 | 
					          dashboardCount: 10,
 | 
				
			||||||
 | 
					          pipelineCount: 3,
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        ingestionCount={0}
 | 
				
			||||||
 | 
					      />,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        wrapper: MemoryRouter,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const mainTitle = getByTestId(container, 'main-title');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(mainTitle).toBeInTheDocument();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('Should have 7 data summary details', () => {
 | 
				
			||||||
 | 
					    const { container } = render(
 | 
				
			||||||
 | 
					      <MyAssetStats
 | 
				
			||||||
 | 
					        countServices={193}
 | 
				
			||||||
 | 
					        entityCounts={{
 | 
				
			||||||
 | 
					          tableCount: 40,
 | 
				
			||||||
 | 
					          topicCount: 13,
 | 
				
			||||||
 | 
					          dashboardCount: 10,
 | 
				
			||||||
 | 
					          pipelineCount: 3,
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        ingestionCount={0}
 | 
				
			||||||
 | 
					      />,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        wrapper: MemoryRouter,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const dataSummary = getByTestId(container, 'data-summary-container');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(dataSummary.childElementCount).toBe(7);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('Should display same count as provided by props', () => {
 | 
				
			||||||
 | 
					    const { container } = render(
 | 
				
			||||||
 | 
					      <MyAssetStats
 | 
				
			||||||
 | 
					        countServices={4}
 | 
				
			||||||
 | 
					        entityCounts={{
 | 
				
			||||||
 | 
					          tableCount: 40,
 | 
				
			||||||
 | 
					          topicCount: 13,
 | 
				
			||||||
 | 
					          dashboardCount: 10,
 | 
				
			||||||
 | 
					          pipelineCount: 3,
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        ingestionCount={0}
 | 
				
			||||||
 | 
					      />,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        wrapper: MemoryRouter,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(getByText(container, /40 tables/i)).toBeInTheDocument();
 | 
				
			||||||
 | 
					    expect(getByText(container, /13 topics/i)).toBeInTheDocument();
 | 
				
			||||||
 | 
					    expect(getByText(container, /10 dashboards/i)).toBeInTheDocument();
 | 
				
			||||||
 | 
					    expect(getByText(container, /3 pipelines/i)).toBeInTheDocument();
 | 
				
			||||||
 | 
					    expect(getByText(container, /4 services/i)).toBeInTheDocument();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('OnClick it should redirect to respective page', () => {
 | 
				
			||||||
 | 
					    const { container } = render(
 | 
				
			||||||
 | 
					      <MyAssetStats
 | 
				
			||||||
 | 
					        countServices={4}
 | 
				
			||||||
 | 
					        entityCounts={{
 | 
				
			||||||
 | 
					          tableCount: 40,
 | 
				
			||||||
 | 
					          topicCount: 13,
 | 
				
			||||||
 | 
					          dashboardCount: 10,
 | 
				
			||||||
 | 
					          pipelineCount: 3,
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        ingestionCount={0}
 | 
				
			||||||
 | 
					      />,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        wrapper: MemoryRouter,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const tables = getByTestId(container, 'tables');
 | 
				
			||||||
 | 
					    const topics = getByTestId(container, 'topics');
 | 
				
			||||||
 | 
					    const dashboards = getByTestId(container, 'dashboards');
 | 
				
			||||||
 | 
					    const pipelines = getByTestId(container, 'pipelines');
 | 
				
			||||||
 | 
					    const service = getByTestId(container, 'service');
 | 
				
			||||||
 | 
					    const user = getByTestId(container, 'user');
 | 
				
			||||||
 | 
					    const terms = getByTestId(container, 'terms');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(tables).toHaveAttribute('href', '/explore/tables');
 | 
				
			||||||
 | 
					    expect(topics).toHaveAttribute('href', '/explore/topics');
 | 
				
			||||||
 | 
					    expect(dashboards).toHaveAttribute('href', '/explore/dashboards');
 | 
				
			||||||
 | 
					    expect(pipelines).toHaveAttribute('href', '/explore/pipelines');
 | 
				
			||||||
 | 
					    expect(service).toHaveAttribute('href', '/services');
 | 
				
			||||||
 | 
					    expect(user).toHaveAttribute('href', '/teams');
 | 
				
			||||||
 | 
					    expect(terms).toHaveAttribute('href', '/teams');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -11,157 +11,206 @@
 | 
				
			|||||||
 *  limitations under the License.
 | 
					 *  limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { isEmpty } from 'lodash';
 | 
					import { observer } from 'mobx-react';
 | 
				
			||||||
import { FormatedTableData } from 'Models';
 | 
					import React, {
 | 
				
			||||||
import React, { useEffect, useRef, useState } from 'react';
 | 
					  Fragment,
 | 
				
			||||||
import { Ownership } from '../../enums/mydata.enum';
 | 
					  useCallback,
 | 
				
			||||||
import { formatDataResponse } from '../../utils/APIUtils';
 | 
					  useEffect,
 | 
				
			||||||
import { getCurrentUserId } from '../../utils/CommonUtils';
 | 
					  useRef,
 | 
				
			||||||
 | 
					  useState,
 | 
				
			||||||
 | 
					} from 'react';
 | 
				
			||||||
 | 
					import { Link } from 'react-router-dom';
 | 
				
			||||||
 | 
					import AppState from '../../AppState';
 | 
				
			||||||
 | 
					import { getExplorePathWithSearch } from '../../constants/constants';
 | 
				
			||||||
 | 
					import { filterList } from '../../constants/Mydata.constants';
 | 
				
			||||||
 | 
					import { FeedFilter, Ownership } from '../../enums/mydata.enum';
 | 
				
			||||||
 | 
					import { getOwnerIds } from '../../utils/CommonUtils';
 | 
				
			||||||
 | 
					import { getSummary } from '../../utils/EntityVersionUtils';
 | 
				
			||||||
 | 
					import { dropdownIcon as DropDownIcon } from '../../utils/svgconstant';
 | 
				
			||||||
 | 
					import { getRelativeDateByTimeStamp } from '../../utils/TimeUtils';
 | 
				
			||||||
 | 
					import { Button } from '../buttons/Button/Button';
 | 
				
			||||||
import ErrorPlaceHolderES from '../common/error-with-placeholder/ErrorPlaceHolderES';
 | 
					import ErrorPlaceHolderES from '../common/error-with-placeholder/ErrorPlaceHolderES';
 | 
				
			||||||
import PageContainer from '../containers/PageContainer';
 | 
					import FeedCards from '../common/FeedCard/FeedCards.component';
 | 
				
			||||||
import MyDataHeader from '../MyDataHeader/MyDataHeader.component';
 | 
					import PageLayout from '../containers/PageLayout';
 | 
				
			||||||
 | 
					import DropDownList from '../dropdown/DropDownList';
 | 
				
			||||||
 | 
					import EntityList from '../EntityList/EntityList';
 | 
				
			||||||
 | 
					import MyAssetStats from '../MyAssetStats/MyAssetStats.component';
 | 
				
			||||||
 | 
					import Onboarding from '../onboarding/Onboarding';
 | 
				
			||||||
import RecentlyViewed from '../recently-viewed/RecentlyViewed';
 | 
					import RecentlyViewed from '../recently-viewed/RecentlyViewed';
 | 
				
			||||||
import SearchedData from '../searched-data/SearchedData';
 | 
					import RecentSearchedTerms from '../RecentSearchedTerms/RecentSearchedTerms';
 | 
				
			||||||
import { MyDataProps } from './MyData.interface';
 | 
					import { MyDataProps } from './MyData.interface';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MyData: React.FC<MyDataProps> = ({
 | 
					const MyData: React.FC<MyDataProps> = ({
 | 
				
			||||||
  error,
 | 
					  error,
 | 
				
			||||||
  countServices,
 | 
					  countServices,
 | 
				
			||||||
  ingestionCount,
 | 
					  ingestionCount,
 | 
				
			||||||
  userDetails,
 | 
					  ownedData,
 | 
				
			||||||
  searchResult,
 | 
					  followedData,
 | 
				
			||||||
  fetchData,
 | 
					 | 
				
			||||||
  entityCounts,
 | 
					  entityCounts,
 | 
				
			||||||
 | 
					  feedData,
 | 
				
			||||||
 | 
					  feedFilter,
 | 
				
			||||||
 | 
					  feedFilterHandler,
 | 
				
			||||||
}: MyDataProps): React.ReactElement => {
 | 
					}: MyDataProps): React.ReactElement => {
 | 
				
			||||||
  const [data, setData] = useState<Array<FormatedTableData>>([]);
 | 
					  const [fieldListVisible, setFieldListVisible] = useState<boolean>(false);
 | 
				
			||||||
  const [currentPage, setCurrentPage] = useState<number>(1);
 | 
					 | 
				
			||||||
  const [totalNumberOfValue, setTotalNumberOfValues] = useState<number>(0);
 | 
					 | 
				
			||||||
  const [isEntityLoading, setIsEntityLoading] = useState<boolean>(true);
 | 
					 | 
				
			||||||
  const [currentTab, setCurrentTab] = useState<number>(1);
 | 
					 | 
				
			||||||
  const [filter, setFilter] = useState<string>('');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const isMounted = useRef(false);
 | 
					  const isMounted = useRef(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getActiveTabClass = (tab: number) => {
 | 
					  const handleDropDown = (
 | 
				
			||||||
    return tab === currentTab ? 'active' : '';
 | 
					    _e: React.MouseEvent<HTMLElement, MouseEvent>,
 | 
				
			||||||
 | 
					    value?: string
 | 
				
			||||||
 | 
					  ) => {
 | 
				
			||||||
 | 
					    feedFilterHandler((value as FeedFilter) || FeedFilter.ALL);
 | 
				
			||||||
 | 
					    setFieldListVisible(false);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  const getFilterDropDown = () => {
 | 
				
			||||||
  const getFilters = (): string => {
 | 
					 | 
				
			||||||
    if (filter === 'owner' && userDetails.teams) {
 | 
					 | 
				
			||||||
      const userTeams = !isEmpty(userDetails)
 | 
					 | 
				
			||||||
        ? userDetails.teams.map((team) => `${filter}:${team.id}`)
 | 
					 | 
				
			||||||
        : [];
 | 
					 | 
				
			||||||
      const ownerIds = [...userTeams, `${filter}:${getCurrentUserId()}`];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return `(${ownerIds.join(' OR ')})`;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return `${filter}:${getCurrentUserId()}`;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleTabChange = (tab: number, filter: string) => {
 | 
					 | 
				
			||||||
    if (currentTab !== tab) {
 | 
					 | 
				
			||||||
      setIsEntityLoading(true);
 | 
					 | 
				
			||||||
      setCurrentTab(tab);
 | 
					 | 
				
			||||||
      setFilter(filter);
 | 
					 | 
				
			||||||
      setCurrentPage(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const getTabs = () => {
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className="tw-mb-3 tw--mt-4" data-testid="tabs">
 | 
					      <Fragment>
 | 
				
			||||||
        <nav className="tw-flex tw-flex-row tw-gh-tabs-container tw-px-4">
 | 
					        <div className="tw-relative tw-mt-5">
 | 
				
			||||||
          <button
 | 
					          <Button
 | 
				
			||||||
            className={`tw-pb-2 tw-px-4 tw-gh-tabs ${getActiveTabClass(1)}`}
 | 
					            data-testid="feeds"
 | 
				
			||||||
            data-testid="tab"
 | 
					            size="custom"
 | 
				
			||||||
            id="recentlyViewedTab"
 | 
					            theme="default"
 | 
				
			||||||
            onClick={() => handleTabChange(1, '')}>
 | 
					            variant="text"
 | 
				
			||||||
            Recently Viewed
 | 
					            onClick={() => setFieldListVisible((visible) => !visible)}>
 | 
				
			||||||
          </button>
 | 
					            <span className="tw-text-grey-body tw-font-normal">
 | 
				
			||||||
          <button
 | 
					              {filterList.find((f) => f.value === feedFilter)?.name}
 | 
				
			||||||
            className={`tw-pb-2 tw-px-4 tw-gh-tabs ${getActiveTabClass(2)}`}
 | 
					            </span>
 | 
				
			||||||
            data-testid="tab"
 | 
					            <DropDownIcon />
 | 
				
			||||||
            id="myDataTab"
 | 
					          </Button>
 | 
				
			||||||
            onClick={() => handleTabChange(2, Ownership.OWNER)}>
 | 
					          {fieldListVisible && (
 | 
				
			||||||
            My Data
 | 
					            <DropDownList
 | 
				
			||||||
          </button>
 | 
					              dropDownList={filterList}
 | 
				
			||||||
          <button
 | 
					              value={feedFilter}
 | 
				
			||||||
            className={`tw-pb-2 tw-px-4 tw-gh-tabs ${getActiveTabClass(3)}`}
 | 
					              onSelect={handleDropDown}
 | 
				
			||||||
            data-testid="tab"
 | 
					            />
 | 
				
			||||||
            id="followingTab"
 | 
					          )}
 | 
				
			||||||
            onClick={() => handleTabChange(3, Ownership.FOLLOWERS)}>
 | 
					        </div>
 | 
				
			||||||
            Following
 | 
					      </Fragment>
 | 
				
			||||||
          </button>
 | 
					    );
 | 
				
			||||||
        </nav>
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getLinkByFilter = (filter: Ownership) => {
 | 
				
			||||||
 | 
					    return `${getExplorePathWithSearch()}?${filter}=${getOwnerIds(
 | 
				
			||||||
 | 
					      filter,
 | 
				
			||||||
 | 
					      AppState.userDetails
 | 
				
			||||||
 | 
					    ).join()}`;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getLeftPanel = () => {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <div className="tw-mt-5">
 | 
				
			||||||
 | 
					        <MyAssetStats
 | 
				
			||||||
 | 
					          countServices={countServices}
 | 
				
			||||||
 | 
					          entityCounts={entityCounts}
 | 
				
			||||||
 | 
					          ingestionCount={ingestionCount}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <div className="tw-filter-seperator" />
 | 
				
			||||||
 | 
					        <RecentlyViewed />
 | 
				
			||||||
 | 
					        <div className="tw-filter-seperator tw-mt-3" />
 | 
				
			||||||
 | 
					        <RecentSearchedTerms />
 | 
				
			||||||
 | 
					        <div className="tw-filter-seperator tw-mt-3" />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const paginate = (pageNumber: number) => {
 | 
					  const getRightPanel = useCallback(() => {
 | 
				
			||||||
    setCurrentPage(pageNumber);
 | 
					    return (
 | 
				
			||||||
  };
 | 
					      <div className="tw-mt-5">
 | 
				
			||||||
 | 
					        <EntityList
 | 
				
			||||||
 | 
					          entityList={ownedData}
 | 
				
			||||||
 | 
					          headerText={
 | 
				
			||||||
 | 
					            <div className="tw-flex tw-justify-between">
 | 
				
			||||||
 | 
					              My Data
 | 
				
			||||||
 | 
					              {ownedData.length ? (
 | 
				
			||||||
 | 
					                <Link
 | 
				
			||||||
 | 
					                  data-testid="my-data"
 | 
				
			||||||
 | 
					                  to={getLinkByFilter(Ownership.OWNER)}>
 | 
				
			||||||
 | 
					                  <span className="link-text tw-font-light tw-text-xs">
 | 
				
			||||||
 | 
					                    View All
 | 
				
			||||||
 | 
					                  </span>
 | 
				
			||||||
 | 
					                </Link>
 | 
				
			||||||
 | 
					              ) : null}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          noDataPlaceholder={<>You have not owned anything yet!</>}
 | 
				
			||||||
 | 
					          testIDText="My data"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <div className="tw-filter-seperator tw-mt-3" />
 | 
				
			||||||
 | 
					        <EntityList
 | 
				
			||||||
 | 
					          entityList={followedData}
 | 
				
			||||||
 | 
					          headerText={
 | 
				
			||||||
 | 
					            <div className="tw-flex tw-justify-between">
 | 
				
			||||||
 | 
					              Following
 | 
				
			||||||
 | 
					              {followedData.length ? (
 | 
				
			||||||
 | 
					                <Link
 | 
				
			||||||
 | 
					                  data-testid="following-data"
 | 
				
			||||||
 | 
					                  to={getLinkByFilter(Ownership.FOLLOWERS)}>
 | 
				
			||||||
 | 
					                  <span className="link-text tw-font-light tw-text-xs">
 | 
				
			||||||
 | 
					                    View All
 | 
				
			||||||
 | 
					                  </span>
 | 
				
			||||||
 | 
					                </Link>
 | 
				
			||||||
 | 
					              ) : null}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          noDataPlaceholder={<>You have not followed anything yet!</>}
 | 
				
			||||||
 | 
					          testIDText="Following data"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <div className="tw-filter-seperator tw-mt-3" />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }, [ownedData, followedData]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  const getFeedsData = useCallback(() => {
 | 
				
			||||||
    if (isMounted.current && Boolean(currentTab === 2 || currentTab === 3)) {
 | 
					    const feeds = feedData
 | 
				
			||||||
      setIsEntityLoading(true);
 | 
					      .map((f) => ({
 | 
				
			||||||
      fetchData({
 | 
					        name: f.name,
 | 
				
			||||||
        queryString: '',
 | 
					        fqn: f.fullyQualifiedName,
 | 
				
			||||||
        from: currentPage,
 | 
					        entityType: f.entityType,
 | 
				
			||||||
        filters: filter ? getFilters() : '',
 | 
					        changeDescriptions: f.changeDescriptions,
 | 
				
			||||||
        sortField: '',
 | 
					      }))
 | 
				
			||||||
        sortOrder: '',
 | 
					      .map((d) => {
 | 
				
			||||||
      });
 | 
					        return (
 | 
				
			||||||
    }
 | 
					          d.changeDescriptions
 | 
				
			||||||
  }, [currentPage, filter]);
 | 
					            .filter((c) => c.fieldsAdded || c.fieldsDeleted || c.fieldsUpdated)
 | 
				
			||||||
 | 
					            .map((change) => ({
 | 
				
			||||||
 | 
					              updatedAt: change.updatedAt,
 | 
				
			||||||
 | 
					              updatedBy: change.updatedBy,
 | 
				
			||||||
 | 
					              entityName: d.name,
 | 
				
			||||||
 | 
					              description: <div>{getSummary(change, true)}</div>,
 | 
				
			||||||
 | 
					              entityType: d.entityType,
 | 
				
			||||||
 | 
					              fqn: d.fqn,
 | 
				
			||||||
 | 
					              relativeDay: getRelativeDateByTimeStamp(change.updatedAt),
 | 
				
			||||||
 | 
					            })) || []
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .flat(1)
 | 
				
			||||||
 | 
					      .sort((a, b) => b.updatedAt - a.updatedAt);
 | 
				
			||||||
 | 
					    const relativeDays = [...new Set(feeds.map((f) => f.relativeDay))];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					    return { feeds, relativeDays };
 | 
				
			||||||
    if (searchResult) {
 | 
					  }, [feedData]);
 | 
				
			||||||
      const hits = searchResult.data.hits.hits;
 | 
					 | 
				
			||||||
      if (hits.length > 0) {
 | 
					 | 
				
			||||||
        setTotalNumberOfValues(searchResult.data.hits.total.value);
 | 
					 | 
				
			||||||
        setData(formatDataResponse(hits));
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        setData([]);
 | 
					 | 
				
			||||||
        setTotalNumberOfValues(0);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setIsEntityLoading(false);
 | 
					 | 
				
			||||||
  }, [searchResult]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    isMounted.current = true;
 | 
					    isMounted.current = true;
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <PageContainer>
 | 
					    <PageLayout leftPanel={getLeftPanel()} rightPanel={getRightPanel()}>
 | 
				
			||||||
      <div className="container-fluid" data-testid="fluid-container">
 | 
					      {error ? (
 | 
				
			||||||
        <MyDataHeader
 | 
					        <ErrorPlaceHolderES errorMessage={error} type="error" />
 | 
				
			||||||
          countServices={countServices}
 | 
					      ) : (
 | 
				
			||||||
          entityCounts={entityCounts}
 | 
					        <Fragment>
 | 
				
			||||||
          ingestionCount={ingestionCount}
 | 
					          {getFeedsData().feeds.length > 0 ? (
 | 
				
			||||||
        />
 | 
					            <Fragment>
 | 
				
			||||||
        {getTabs()}
 | 
					              {getFilterDropDown()}
 | 
				
			||||||
        {error && Boolean(currentTab === 2 || currentTab === 3) ? (
 | 
					              <FeedCards {...getFeedsData()} />
 | 
				
			||||||
          <ErrorPlaceHolderES errorMessage={error} type="error" />
 | 
					            </Fragment>
 | 
				
			||||||
        ) : (
 | 
					          ) : (
 | 
				
			||||||
          <SearchedData
 | 
					            <Onboarding showLogo={false} />
 | 
				
			||||||
            showOnboardingTemplate
 | 
					          )}
 | 
				
			||||||
            currentPage={currentPage}
 | 
					        </Fragment>
 | 
				
			||||||
            data={data}
 | 
					      )}
 | 
				
			||||||
            isLoading={currentTab === 1 ? false : isEntityLoading}
 | 
					    </PageLayout>
 | 
				
			||||||
            paginate={paginate}
 | 
					 | 
				
			||||||
            searchText="*"
 | 
					 | 
				
			||||||
            showOnlyChildren={currentTab === 1}
 | 
					 | 
				
			||||||
            showResultCount={filter && data.length > 0 ? true : false}
 | 
					 | 
				
			||||||
            totalValue={totalNumberOfValue}>
 | 
					 | 
				
			||||||
            {currentTab === 1 ? <RecentlyViewed /> : null}
 | 
					 | 
				
			||||||
          </SearchedData>
 | 
					 | 
				
			||||||
        )}
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </PageContainer>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default MyData;
 | 
					export default observer(MyData);
 | 
				
			||||||
 | 
				
			|||||||
@ -11,15 +11,33 @@
 | 
				
			|||||||
 *  limitations under the License.
 | 
					 *  limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { EntityCounts, SearchDataFunctionType, SearchResponse } from 'Models';
 | 
					import {
 | 
				
			||||||
import { User } from '../../generated/entity/teams/user';
 | 
					  EntityCounts,
 | 
				
			||||||
 | 
					  FormatedTableData,
 | 
				
			||||||
 | 
					  SearchDataFunctionType,
 | 
				
			||||||
 | 
					  SearchResponse,
 | 
				
			||||||
 | 
					} from 'Models';
 | 
				
			||||||
 | 
					import { FeedFilter } from '../../enums/mydata.enum';
 | 
				
			||||||
 | 
					import { ChangeDescription, User } from '../../generated/entity/teams/user';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface MyDataProps {
 | 
					export interface MyDataProps {
 | 
				
			||||||
  error: string;
 | 
					  error: string;
 | 
				
			||||||
  ingestionCount: number;
 | 
					  ingestionCount: number;
 | 
				
			||||||
  countServices: number;
 | 
					  countServices: number;
 | 
				
			||||||
  userDetails: User;
 | 
					  userDetails?: User;
 | 
				
			||||||
  searchResult: SearchResponse | undefined;
 | 
					  searchResult: SearchResponse | undefined;
 | 
				
			||||||
  fetchData: (value: SearchDataFunctionType) => void;
 | 
					  ownedData: Array<FormatedTableData>;
 | 
				
			||||||
 | 
					  followedData: Array<FormatedTableData>;
 | 
				
			||||||
 | 
					  feedData: Array<
 | 
				
			||||||
 | 
					    FormatedTableData & {
 | 
				
			||||||
 | 
					      entityType: string;
 | 
				
			||||||
 | 
					      changeDescriptions: Array<
 | 
				
			||||||
 | 
					        ChangeDescription & { updatedAt: number; updatedBy: string }
 | 
				
			||||||
 | 
					      >;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  >;
 | 
				
			||||||
 | 
					  feedFilter: string;
 | 
				
			||||||
 | 
					  feedFilterHandler: (v: FeedFilter) => void;
 | 
				
			||||||
 | 
					  fetchData?: (value: SearchDataFunctionType) => void;
 | 
				
			||||||
  entityCounts: EntityCounts;
 | 
					  entityCounts: EntityCounts;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,7 @@ import { SearchResponse } from 'Models';
 | 
				
			|||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import { MemoryRouter } from 'react-router-dom';
 | 
					import { MemoryRouter } from 'react-router-dom';
 | 
				
			||||||
import { User } from '../../generated/entity/teams/user';
 | 
					import { User } from '../../generated/entity/teams/user';
 | 
				
			||||||
 | 
					import { formatDataResponse } from '../../utils/APIUtils';
 | 
				
			||||||
import MyDataPage from './MyData.component';
 | 
					import MyDataPage from './MyData.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mockData = {
 | 
					const mockData = {
 | 
				
			||||||
@ -247,6 +248,8 @@ jest.mock('../../utils/ServiceUtils', () => ({
 | 
				
			|||||||
  getTotalEntityCountByService: jest.fn().mockReturnValue(2),
 | 
					  getTotalEntityCountByService: jest.fn().mockReturnValue(2),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const feedFilterHandler = jest.fn();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const fetchData = jest.fn();
 | 
					const fetchData = jest.fn();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('Test MyData page', () => {
 | 
					describe('Test MyData page', () => {
 | 
				
			||||||
@ -261,8 +264,13 @@ describe('Test MyData page', () => {
 | 
				
			|||||||
          pipelineCount: 1,
 | 
					          pipelineCount: 1,
 | 
				
			||||||
        }}
 | 
					        }}
 | 
				
			||||||
        error=""
 | 
					        error=""
 | 
				
			||||||
 | 
					        feedData={formatDataResponse(mockData.data.hits.hits)}
 | 
				
			||||||
 | 
					        feedFilter=""
 | 
				
			||||||
 | 
					        feedFilterHandler={feedFilterHandler}
 | 
				
			||||||
        fetchData={fetchData}
 | 
					        fetchData={fetchData}
 | 
				
			||||||
 | 
					        followedData={formatDataResponse(mockData.data.hits.hits)}
 | 
				
			||||||
        ingestionCount={0}
 | 
					        ingestionCount={0}
 | 
				
			||||||
 | 
					        ownedData={formatDataResponse(mockData.data.hits.hits)}
 | 
				
			||||||
        searchResult={mockData as unknown as SearchResponse}
 | 
					        searchResult={mockData as unknown as SearchResponse}
 | 
				
			||||||
        userDetails={mockUserDetails as unknown as User}
 | 
					        userDetails={mockUserDetails as unknown as User}
 | 
				
			||||||
      />,
 | 
					      />,
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Copyright 2021 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 React, { FunctionComponent } from 'react';
 | 
				
			||||||
 | 
					import { Link } from 'react-router-dom';
 | 
				
			||||||
 | 
					import { getExplorePathWithSearch } from '../../constants/constants';
 | 
				
			||||||
 | 
					import { getRecentlySearchedData } from '../../utils/CommonUtils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const RecentSearchedTerms: FunctionComponent = () => {
 | 
				
			||||||
 | 
					  const recentlySearchedTerms = getRecentlySearchedData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <h6 className="tw-heading tw-mb-3" data-testid="filter-heading">
 | 
				
			||||||
 | 
					        Recently Searched Terms
 | 
				
			||||||
 | 
					      </h6>
 | 
				
			||||||
 | 
					      {recentlySearchedTerms.length ? (
 | 
				
			||||||
 | 
					        recentlySearchedTerms.map((item, index) => {
 | 
				
			||||||
 | 
					          return (
 | 
				
			||||||
 | 
					            <div
 | 
				
			||||||
 | 
					              className="tw-flex tw-items-center tw-justify-between tw-mb-2"
 | 
				
			||||||
 | 
					              data-testid={`Recently-Search-${item.term}`}
 | 
				
			||||||
 | 
					              key={index}>
 | 
				
			||||||
 | 
					              <div className="tw-flex">
 | 
				
			||||||
 | 
					                <Link
 | 
				
			||||||
 | 
					                  className="tw-font-medium"
 | 
				
			||||||
 | 
					                  to={getExplorePathWithSearch(item.term)}>
 | 
				
			||||||
 | 
					                  <button className="tw-text-grey-body hover:tw-text-primary-hover hover:tw-underline">
 | 
				
			||||||
 | 
					                    <i className="fa fa-search tw-text-grey-muted tw-pr-2" />
 | 
				
			||||||
 | 
					                    {item.term}
 | 
				
			||||||
 | 
					                  </button>
 | 
				
			||||||
 | 
					                </Link>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        <>No searched terms!</>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default RecentSearchedTerms;
 | 
				
			||||||
@ -34,7 +34,7 @@ import {
 | 
				
			|||||||
import { urlGitbookDocs, urlJoinSlack } from '../../constants/url.const';
 | 
					import { urlGitbookDocs, urlJoinSlack } from '../../constants/url.const';
 | 
				
			||||||
import { useAuth } from '../../hooks/authHooks';
 | 
					import { useAuth } from '../../hooks/authHooks';
 | 
				
			||||||
import { userSignOut } from '../../utils/AuthUtils';
 | 
					import { userSignOut } from '../../utils/AuthUtils';
 | 
				
			||||||
import { addToRecentSearch } from '../../utils/CommonUtils';
 | 
					import { addToRecentSearched } from '../../utils/CommonUtils';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  inPageSearchOptions,
 | 
					  inPageSearchOptions,
 | 
				
			||||||
  isInPageSearchAllowed,
 | 
					  isInPageSearchAllowed,
 | 
				
			||||||
@ -215,7 +215,7 @@ const Appbar: React.FC = (): JSX.Element => {
 | 
				
			|||||||
                  const target = e.target as HTMLInputElement;
 | 
					                  const target = e.target as HTMLInputElement;
 | 
				
			||||||
                  if (e.key === 'Enter') {
 | 
					                  if (e.key === 'Enter') {
 | 
				
			||||||
                    setIsOpen(false);
 | 
					                    setIsOpen(false);
 | 
				
			||||||
                    addToRecentSearch(target.value);
 | 
					                    addToRecentSearched(target.value);
 | 
				
			||||||
                    history.push(
 | 
					                    history.push(
 | 
				
			||||||
                      getExplorePathWithSearch(
 | 
					                      getExplorePathWithSearch(
 | 
				
			||||||
                        target.value,
 | 
					                        target.value,
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Copyright 2021 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 React, { FC, Fragment, ReactNode } from 'react';
 | 
				
			||||||
 | 
					import { Link } from 'react-router-dom';
 | 
				
			||||||
 | 
					import { getEntityLink } from '../../../utils/TableUtils';
 | 
				
			||||||
 | 
					import { getTimeByTimeStamp } from '../../../utils/TimeUtils';
 | 
				
			||||||
 | 
					import Avatar from '../avatar/Avatar';
 | 
				
			||||||
 | 
					interface Feed {
 | 
				
			||||||
 | 
					  updatedAt: number;
 | 
				
			||||||
 | 
					  updatedBy: string;
 | 
				
			||||||
 | 
					  description: ReactNode;
 | 
				
			||||||
 | 
					  entityName: string;
 | 
				
			||||||
 | 
					  entityType: string;
 | 
				
			||||||
 | 
					  fqn: string;
 | 
				
			||||||
 | 
					  relativeDay: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface FeedCardsProp {
 | 
				
			||||||
 | 
					  feeds: Array<Feed>;
 | 
				
			||||||
 | 
					  relativeDays: Array<string>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const FeedCards: FC<FeedCardsProp> = ({
 | 
				
			||||||
 | 
					  feeds = [],
 | 
				
			||||||
 | 
					  relativeDays = [],
 | 
				
			||||||
 | 
					}: FeedCardsProp) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Fragment>
 | 
				
			||||||
 | 
					      {relativeDays.map((d, i) => (
 | 
				
			||||||
 | 
					        <div className="tw-grid tw-grid-rows-1 tw-grid-cols-1 tw-mt-3" key={i}>
 | 
				
			||||||
 | 
					          <div className="tw-relative tw-mb-3">
 | 
				
			||||||
 | 
					            <div className="tw-flex tw-justify-center">
 | 
				
			||||||
 | 
					              <hr className="tw-absolute tw-top-3 tw-border-b-2 tw-border-main tw-w-full tw-z-0" />
 | 
				
			||||||
 | 
					              <span className="tw-bg-white tw-px-4 tw-py-px tw-border tw-border-main tw-rounded tw-z-10 tw-text-grey-muted tw-font-normal">
 | 
				
			||||||
 | 
					                {d}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          {feeds
 | 
				
			||||||
 | 
					            .filter((f) => f.relativeDay === d)
 | 
				
			||||||
 | 
					            .map((feed, i) => (
 | 
				
			||||||
 | 
					              <div
 | 
				
			||||||
 | 
					                className="tw-bg-white tw-p-3 tw-border tw-border-main tw-rounded-md tw-mb-3"
 | 
				
			||||||
 | 
					                key={i}>
 | 
				
			||||||
 | 
					                <div className="tw-flex tw-mb-1">
 | 
				
			||||||
 | 
					                  <Avatar name={feed.updatedBy} width="24" />
 | 
				
			||||||
 | 
					                  <h6 className="tw-flex tw-items-center tw-m-0 tw-heading tw-pl-2">
 | 
				
			||||||
 | 
					                    {feed.updatedBy}
 | 
				
			||||||
 | 
					                    <span className="tw-pl-1 tw-font-normal">
 | 
				
			||||||
 | 
					                      updated{' '}
 | 
				
			||||||
 | 
					                      <Link to={getEntityLink(feed.entityType, feed.fqn)}>
 | 
				
			||||||
 | 
					                        <span className="link-text">{feed.entityName}</span>
 | 
				
			||||||
 | 
					                      </Link>
 | 
				
			||||||
 | 
					                      <span className="tw-text-grey-muted tw-pl-1 tw-text-xs">
 | 
				
			||||||
 | 
					                        {getTimeByTimeStamp(feed.updatedAt)}
 | 
				
			||||||
 | 
					                      </span>
 | 
				
			||||||
 | 
					                    </span>
 | 
				
			||||||
 | 
					                  </h6>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div className="tw-pl-7">{feed.description}</div>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      ))}
 | 
				
			||||||
 | 
					    </Fragment>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default FeedCards;
 | 
				
			||||||
@ -11,7 +11,8 @@
 | 
				
			|||||||
 *  limitations under the License.
 | 
					 *  limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import React from 'react';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
 | 
					import React, { FC } from 'react';
 | 
				
			||||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
 | 
					import SVGIcons, { Icons } from '../../utils/SvgUtils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const data = [
 | 
					const data = [
 | 
				
			||||||
@ -20,10 +21,18 @@ const data = [
 | 
				
			|||||||
  'Follow the datasets that you frequently use to stay informed about it.',
 | 
					  'Follow the datasets that you frequently use to stay informed about it.',
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Onboarding: React.FC = () => {
 | 
					interface OnboardingProp {
 | 
				
			||||||
 | 
					  showLogo?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Onboarding: FC<OnboardingProp> = ({
 | 
				
			||||||
 | 
					  showLogo = true,
 | 
				
			||||||
 | 
					}: OnboardingProp) => {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      className="tw-flex tw-items-center tw-justify-around tw-mt-20"
 | 
					      className={classNames(
 | 
				
			||||||
 | 
					        'tw-flex tw-items-center tw-justify-around tw-mt-10'
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
      data-testid="onboarding">
 | 
					      data-testid="onboarding">
 | 
				
			||||||
      <div className="tw-p-4" style={{ maxWidth: '700px' }}>
 | 
					      <div className="tw-p-4" style={{ maxWidth: '700px' }}>
 | 
				
			||||||
        <div className="tw-mb-6">
 | 
					        <div className="tw-mb-6">
 | 
				
			||||||
@ -49,21 +58,17 @@ const Onboarding: React.FC = () => {
 | 
				
			|||||||
          ))}
 | 
					          ))}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					      {showLogo ? (
 | 
				
			||||||
      <div>
 | 
					        <div>
 | 
				
			||||||
        {/* <img
 | 
					          <SVGIcons
 | 
				
			||||||
          alt=""
 | 
					            alt="OpenMetadata Logo"
 | 
				
			||||||
          className="tw-h-auto tw-w-full tw-filter tw-grayscale tw-opacity-50"
 | 
					            className="tw-h-auto tw-filter tw-grayscale tw-opacity-50"
 | 
				
			||||||
          src={logo}
 | 
					            data-testid="logo"
 | 
				
			||||||
        /> */}
 | 
					            icon={Icons.LOGO_SMALL}
 | 
				
			||||||
        <SVGIcons
 | 
					            width="350"
 | 
				
			||||||
          alt="OpenMetadata Logo"
 | 
					          />
 | 
				
			||||||
          className="tw-h-auto tw-filter tw-grayscale tw-opacity-50"
 | 
					        </div>
 | 
				
			||||||
          data-testid="logo"
 | 
					      ) : null}
 | 
				
			||||||
          icon={Icons.LOGO_SMALL}
 | 
					 | 
				
			||||||
          width="350"
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -11,7 +11,6 @@
 | 
				
			|||||||
 *  limitations under the License.
 | 
					 *  limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { isString } from 'lodash';
 | 
					 | 
				
			||||||
import { FormatedTableData } from 'Models';
 | 
					import { FormatedTableData } from 'Models';
 | 
				
			||||||
import React, { FunctionComponent, useEffect, useState } from 'react';
 | 
					import React, { FunctionComponent, useEffect, useState } from 'react';
 | 
				
			||||||
import { getDashboardByFqn } from '../../axiosAPIs/dashboardAPI';
 | 
					import { getDashboardByFqn } from '../../axiosAPIs/dashboardAPI';
 | 
				
			||||||
@ -26,9 +25,8 @@ import {
 | 
				
			|||||||
} from '../../utils/CommonUtils';
 | 
					} from '../../utils/CommonUtils';
 | 
				
			||||||
import { getOwnerFromId, getTierTags } from '../../utils/TableUtils';
 | 
					import { getOwnerFromId, getTierTags } from '../../utils/TableUtils';
 | 
				
			||||||
import { getTableTags } from '../../utils/TagsUtils';
 | 
					import { getTableTags } from '../../utils/TagsUtils';
 | 
				
			||||||
import TableDataCard from '../common/table-data-card/TableDataCard';
 | 
					import EntityList from '../EntityList/EntityList';
 | 
				
			||||||
import Loader from '../Loader/Loader';
 | 
					import Loader from '../Loader/Loader';
 | 
				
			||||||
import Onboarding from '../onboarding/Onboarding';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const RecentlyViewed: FunctionComponent = () => {
 | 
					const RecentlyViewed: FunctionComponent = () => {
 | 
				
			||||||
  const recentlyViewedData = getRecentlyViewedData();
 | 
					  const recentlyViewedData = getRecentlyViewedData();
 | 
				
			||||||
@ -184,32 +182,12 @@ const RecentlyViewed: FunctionComponent = () => {
 | 
				
			|||||||
      {isLoading ? (
 | 
					      {isLoading ? (
 | 
				
			||||||
        <Loader />
 | 
					        <Loader />
 | 
				
			||||||
      ) : (
 | 
					      ) : (
 | 
				
			||||||
        <>
 | 
					        <EntityList
 | 
				
			||||||
          {data.length ? (
 | 
					          entityList={data}
 | 
				
			||||||
            data.map((item, index) => {
 | 
					          headerText="Recently Viewed"
 | 
				
			||||||
              return (
 | 
					          noDataPlaceholder={<>No recently viewed data!</>}
 | 
				
			||||||
                <div className="tw-mb-3" key={index}>
 | 
					          testIDText="Recently Viewed"
 | 
				
			||||||
                  <TableDataCard
 | 
					        />
 | 
				
			||||||
                    description={item.description}
 | 
					 | 
				
			||||||
                    fullyQualifiedName={item.fullyQualifiedName}
 | 
					 | 
				
			||||||
                    indexType={item.index}
 | 
					 | 
				
			||||||
                    name={item.name}
 | 
					 | 
				
			||||||
                    owner={item.owner}
 | 
					 | 
				
			||||||
                    serviceType={item.serviceType || '--'}
 | 
					 | 
				
			||||||
                    tableType={item.tableType}
 | 
					 | 
				
			||||||
                    tags={item.tags}
 | 
					 | 
				
			||||||
                    tier={
 | 
					 | 
				
			||||||
                      isString(item.tier) ? item.tier?.split('.')[1] : item.tier
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    usage={item.weeklyPercentileRank}
 | 
					 | 
				
			||||||
                  />
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              );
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
          ) : (
 | 
					 | 
				
			||||||
            <Onboarding />
 | 
					 | 
				
			||||||
          )}
 | 
					 | 
				
			||||||
        </>
 | 
					 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
    </>
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
				
			|||||||
@ -50,3 +50,9 @@ export const getFilters = (
 | 
				
			|||||||
      : `${facetFilterString}`
 | 
					      : `${facetFilterString}`
 | 
				
			||||||
  }`;
 | 
					  }`;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const filterList = [
 | 
				
			||||||
 | 
					  { name: 'All Activity Feeds', value: 'all' },
 | 
				
			||||||
 | 
					  { name: 'My Data Activity Feeds', value: 'owner' },
 | 
				
			||||||
 | 
					  { name: 'Followed Data Activity Feeds', value: 'followers' },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ export const LIST_SIZE = 5;
 | 
				
			|||||||
export const SIDEBAR_WIDTH_COLLAPSED = 290;
 | 
					export const SIDEBAR_WIDTH_COLLAPSED = 290;
 | 
				
			||||||
export const SIDEBAR_WIDTH_EXPANDED = 290;
 | 
					export const SIDEBAR_WIDTH_EXPANDED = 290;
 | 
				
			||||||
export const LOCALSTORAGE_RECENTLY_VIEWED = 'recentlyViewedData';
 | 
					export const LOCALSTORAGE_RECENTLY_VIEWED = 'recentlyViewedData';
 | 
				
			||||||
export const LOCALSTORAGE_RECENTLY_SEARCH = 'recentlySearchData';
 | 
					export const LOCALSTORAGE_RECENTLY_SEARCHED = 'recentlySearchedData';
 | 
				
			||||||
export const oidcTokenKey = 'oidcIdToken';
 | 
					export const oidcTokenKey = 'oidcIdToken';
 | 
				
			||||||
export const imageTypes = {
 | 
					export const imageTypes = {
 | 
				
			||||||
  image: 's96-c',
 | 
					  image: 's96-c',
 | 
				
			||||||
 | 
				
			|||||||
@ -49,7 +49,9 @@ export const getQueryParam = (urlSearchQuery = ''): FilterObject => {
 | 
				
			|||||||
    .map((filter) => {
 | 
					    .map((filter) => {
 | 
				
			||||||
      const arrFilter = filter.split('=');
 | 
					      const arrFilter = filter.split('=');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return { [arrFilter[0]]: [arrFilter[1]] };
 | 
					      return {
 | 
				
			||||||
 | 
					        [arrFilter[0]]: [arrFilter[1]].map((r) => r.split(',')).flat(1),
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .reduce((prev, curr) => {
 | 
					    .reduce((prev, curr) => {
 | 
				
			||||||
      return Object.assign(prev, curr);
 | 
					      return Object.assign(prev, curr);
 | 
				
			||||||
 | 
				
			|||||||
@ -15,3 +15,9 @@ export enum Ownership {
 | 
				
			|||||||
  OWNER = 'owner',
 | 
					  OWNER = 'owner',
 | 
				
			||||||
  FOLLOWERS = 'followers',
 | 
					  FOLLOWERS = 'followers',
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum FeedFilter {
 | 
				
			||||||
 | 
					  ALL = 'all',
 | 
				
			||||||
 | 
					  OWNED = 'owner',
 | 
				
			||||||
 | 
					  FOLLOWING = 'followers',
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -391,15 +391,15 @@ declare module 'Models' {
 | 
				
			|||||||
    timestamp: number;
 | 
					    timestamp: number;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  interface RecentlySearchData {
 | 
					  interface RecentlySearchedData {
 | 
				
			||||||
    term: string;
 | 
					    term: string;
 | 
				
			||||||
    timestamp: number;
 | 
					    timestamp: number;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  export interface RecentlyViewed {
 | 
					  export interface RecentlyViewed {
 | 
				
			||||||
    data: Array<RecentlyViewedData>;
 | 
					    data: Array<RecentlyViewedData>;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  export interface SearchData {
 | 
					  export interface RecentlySearched {
 | 
				
			||||||
    data: Array<RecentlySearchData>;
 | 
					    data: Array<RecentlySearchedData>;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export type DatasetSchemaTableTab = 'schema' | 'sample_data';
 | 
					  export type DatasetSchemaTableTab = 'schema' | 'sample_data';
 | 
				
			||||||
 | 
				
			|||||||
@ -11,25 +11,33 @@
 | 
				
			|||||||
 *  limitations under the License.
 | 
					 *  limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { AxiosError } from 'axios';
 | 
					import { AxiosError, AxiosResponse } from 'axios';
 | 
				
			||||||
import { isUndefined } from 'lodash';
 | 
					import { isEmpty, isNil, isUndefined } from 'lodash';
 | 
				
			||||||
import { observer } from 'mobx-react';
 | 
					import { observer } from 'mobx-react';
 | 
				
			||||||
import { EntityCounts, SearchDataFunctionType, SearchResponse } from 'Models';
 | 
					import { EntityCounts, FormatedTableData, SearchResponse } from 'Models';
 | 
				
			||||||
import React, { useEffect, useState } from 'react';
 | 
					import React, { useEffect, useState } from 'react';
 | 
				
			||||||
 | 
					import { useLocation } from 'react-router-dom';
 | 
				
			||||||
import AppState from '../../AppState';
 | 
					import AppState from '../../AppState';
 | 
				
			||||||
import { getIngestionWorkflows } from '../../axiosAPIs/ingestionWorkflowAPI';
 | 
					import { getIngestionWorkflows } from '../../axiosAPIs/ingestionWorkflowAPI';
 | 
				
			||||||
import { searchData } from '../../axiosAPIs/miscAPI';
 | 
					import { searchData } from '../../axiosAPIs/miscAPI';
 | 
				
			||||||
 | 
					import PageContainerV1 from '../../components/containers/PageContainerV1';
 | 
				
			||||||
import Loader from '../../components/Loader/Loader';
 | 
					import Loader from '../../components/Loader/Loader';
 | 
				
			||||||
import MyData from '../../components/MyData/MyData.component';
 | 
					import MyData from '../../components/MyData/MyData.component';
 | 
				
			||||||
import { PAGE_SIZE } from '../../constants/constants';
 | 
					 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  myDataEntityCounts,
 | 
					  myDataEntityCounts,
 | 
				
			||||||
  myDataSearchIndex,
 | 
					  myDataSearchIndex,
 | 
				
			||||||
} from '../../constants/Mydata.constants';
 | 
					} from '../../constants/Mydata.constants';
 | 
				
			||||||
 | 
					import { FeedFilter, Ownership } from '../../enums/mydata.enum';
 | 
				
			||||||
 | 
					import { ChangeDescription } from '../../generated/entity/teams/user';
 | 
				
			||||||
 | 
					import { useAuth } from '../../hooks/authHooks';
 | 
				
			||||||
 | 
					import { formatDataResponse } from '../../utils/APIUtils';
 | 
				
			||||||
import { getEntityCountByType } from '../../utils/EntityUtils';
 | 
					import { getEntityCountByType } from '../../utils/EntityUtils';
 | 
				
			||||||
 | 
					import { getMyDataFilters } from '../../utils/MyDataUtils';
 | 
				
			||||||
import { getAllServices } from '../../utils/ServiceUtils';
 | 
					import { getAllServices } from '../../utils/ServiceUtils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MyDataPage = () => {
 | 
					const MyDataPage = () => {
 | 
				
			||||||
 | 
					  const location = useLocation();
 | 
				
			||||||
 | 
					  const { isAuthDisabled } = useAuth(location.pathname);
 | 
				
			||||||
  const [error, setError] = useState<string>('');
 | 
					  const [error, setError] = useState<string>('');
 | 
				
			||||||
  const [countServices, setCountServices] = useState<number>();
 | 
					  const [countServices, setCountServices] = useState<number>();
 | 
				
			||||||
  const [ingestionCount, setIngestionCount] = useState<number>();
 | 
					  const [ingestionCount, setIngestionCount] = useState<number>();
 | 
				
			||||||
@ -37,18 +45,28 @@ const MyDataPage = () => {
 | 
				
			|||||||
  const [searchResult, setSearchResult] = useState<SearchResponse>();
 | 
					  const [searchResult, setSearchResult] = useState<SearchResponse>();
 | 
				
			||||||
  const [entityCounts, setEntityCounts] = useState<EntityCounts>();
 | 
					  const [entityCounts, setEntityCounts] = useState<EntityCounts>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const fetchData = (value: SearchDataFunctionType, fetchService = false) => {
 | 
					  const [ownedData, setOwnedData] = useState<Array<FormatedTableData>>();
 | 
				
			||||||
 | 
					  const [followedData, setFollowedData] = useState<Array<FormatedTableData>>();
 | 
				
			||||||
 | 
					  const [feedData, setFeedData] = useState<
 | 
				
			||||||
 | 
					    Array<
 | 
				
			||||||
 | 
					      FormatedTableData & {
 | 
				
			||||||
 | 
					        entityType: string;
 | 
				
			||||||
 | 
					        changeDescriptions: Array<
 | 
				
			||||||
 | 
					          ChangeDescription & { updatedAt: number; updatedBy: string }
 | 
				
			||||||
 | 
					        >;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					  >();
 | 
				
			||||||
 | 
					  const [feedFilter, setFeedFilter] = useState<FeedFilter>(FeedFilter.ALL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const feedFilterHandler = (filter: FeedFilter) => {
 | 
				
			||||||
 | 
					    setFeedFilter(filter);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const fetchData = (fetchService = false) => {
 | 
				
			||||||
    setError('');
 | 
					    setError('');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    searchData(
 | 
					    searchData('', 1, 0, '', '', '', myDataSearchIndex)
 | 
				
			||||||
      value.queryString,
 | 
					 | 
				
			||||||
      value.from,
 | 
					 | 
				
			||||||
      value.size ?? PAGE_SIZE,
 | 
					 | 
				
			||||||
      value.filters,
 | 
					 | 
				
			||||||
      value.sortField,
 | 
					 | 
				
			||||||
      value.sortOrder,
 | 
					 | 
				
			||||||
      myDataSearchIndex
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
      .then((res: SearchResponse) => {
 | 
					      .then((res: SearchResponse) => {
 | 
				
			||||||
        setSearchResult(res);
 | 
					        setSearchResult(res);
 | 
				
			||||||
        if (isUndefined(entityCounts)) {
 | 
					        if (isUndefined(entityCounts)) {
 | 
				
			||||||
@ -75,22 +93,84 @@ const MyDataPage = () => {
 | 
				
			|||||||
    setIsLoading(false);
 | 
					    setIsLoading(false);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  const fetchMyData = () => {
 | 
				
			||||||
    fetchData(
 | 
					    const ownedEntity = searchData(
 | 
				
			||||||
      {
 | 
					      '',
 | 
				
			||||||
        queryString: '',
 | 
					      1,
 | 
				
			||||||
        from: 1,
 | 
					      5,
 | 
				
			||||||
        filters: '',
 | 
					      getMyDataFilters(Ownership.OWNER, AppState.userDetails),
 | 
				
			||||||
        size: 0,
 | 
					      'last_updated_timestamp',
 | 
				
			||||||
        sortField: '',
 | 
					      '',
 | 
				
			||||||
        sortOrder: '',
 | 
					      myDataSearchIndex
 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      isUndefined(countServices)
 | 
					 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const followedEntity = searchData(
 | 
				
			||||||
 | 
					      '',
 | 
				
			||||||
 | 
					      1,
 | 
				
			||||||
 | 
					      5,
 | 
				
			||||||
 | 
					      getMyDataFilters(Ownership.FOLLOWERS, AppState.userDetails),
 | 
				
			||||||
 | 
					      'last_updated_timestamp',
 | 
				
			||||||
 | 
					      '',
 | 
				
			||||||
 | 
					      myDataSearchIndex
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Promise.allSettled([ownedEntity, followedEntity]).then(
 | 
				
			||||||
 | 
					      ([resOwnedEntity, resFollowedEntity]) => {
 | 
				
			||||||
 | 
					        if (resOwnedEntity.status === 'fulfilled') {
 | 
				
			||||||
 | 
					          setOwnedData(formatDataResponse(resOwnedEntity.value.data.hits.hits));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (resFollowedEntity.status === 'fulfilled') {
 | 
				
			||||||
 | 
					          setFollowedData(
 | 
				
			||||||
 | 
					            formatDataResponse(resFollowedEntity.value.data.hits.hits)
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getFeedData = () => {
 | 
				
			||||||
 | 
					    searchData(
 | 
				
			||||||
 | 
					      '',
 | 
				
			||||||
 | 
					      1,
 | 
				
			||||||
 | 
					      20,
 | 
				
			||||||
 | 
					      feedFilter !== FeedFilter.ALL
 | 
				
			||||||
 | 
					        ? getMyDataFilters(
 | 
				
			||||||
 | 
					            feedFilter === FeedFilter.OWNED
 | 
				
			||||||
 | 
					              ? Ownership.OWNER
 | 
				
			||||||
 | 
					              : Ownership.FOLLOWERS,
 | 
				
			||||||
 | 
					            AppState.userDetails
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        : '',
 | 
				
			||||||
 | 
					      'last_updated_timestamp',
 | 
				
			||||||
 | 
					      '',
 | 
				
			||||||
 | 
					      myDataSearchIndex
 | 
				
			||||||
 | 
					    ).then((res: AxiosResponse) => {
 | 
				
			||||||
 | 
					      if (res.data) {
 | 
				
			||||||
 | 
					        setFeedData(formatDataResponse(res.data.hits.hits));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    fetchData(true);
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    getFeedData();
 | 
				
			||||||
 | 
					  }, [feedFilter]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      ((isAuthDisabled && AppState.users.length) ||
 | 
				
			||||||
 | 
					        !isEmpty(AppState.userDetails)) &&
 | 
				
			||||||
 | 
					      (isNil(ownedData) || isNil(followedData))
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      fetchMyData();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [AppState.userDetails, AppState.users, isAuthDisabled]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <PageContainerV1>
 | 
				
			||||||
      {!isUndefined(countServices) &&
 | 
					      {!isUndefined(countServices) &&
 | 
				
			||||||
      !isUndefined(entityCounts) &&
 | 
					      !isUndefined(entityCounts) &&
 | 
				
			||||||
      !isUndefined(ingestionCount) &&
 | 
					      !isUndefined(ingestionCount) &&
 | 
				
			||||||
@ -99,15 +179,18 @@ const MyDataPage = () => {
 | 
				
			|||||||
          countServices={countServices}
 | 
					          countServices={countServices}
 | 
				
			||||||
          entityCounts={entityCounts}
 | 
					          entityCounts={entityCounts}
 | 
				
			||||||
          error={error}
 | 
					          error={error}
 | 
				
			||||||
          fetchData={fetchData}
 | 
					          feedData={feedData || []}
 | 
				
			||||||
 | 
					          feedFilter={feedFilter}
 | 
				
			||||||
 | 
					          feedFilterHandler={feedFilterHandler}
 | 
				
			||||||
 | 
					          followedData={followedData || []}
 | 
				
			||||||
          ingestionCount={ingestionCount}
 | 
					          ingestionCount={ingestionCount}
 | 
				
			||||||
 | 
					          ownedData={ownedData || []}
 | 
				
			||||||
          searchResult={searchResult}
 | 
					          searchResult={searchResult}
 | 
				
			||||||
          userDetails={AppState.userDetails}
 | 
					 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      ) : (
 | 
					      ) : (
 | 
				
			||||||
        <Loader />
 | 
					        <Loader />
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
    </>
 | 
					    </PageContainerV1>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -373,7 +373,7 @@ const DatabaseDetails: FunctionComponent = () => {
 | 
				
			|||||||
                setActiveTab={activeTabHandler}
 | 
					                setActiveTab={activeTabHandler}
 | 
				
			||||||
                tabs={tabs}
 | 
					                tabs={tabs}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
              <div className="tw-bg-white tw-flex-grow">
 | 
					              <div className="tw-bg-white tw-flex-grow tw-py-4">
 | 
				
			||||||
                {activeTab === 1 && (
 | 
					                {activeTab === 1 && (
 | 
				
			||||||
                  <>
 | 
					                  <>
 | 
				
			||||||
                    <table
 | 
					                    <table
 | 
				
			||||||
 | 
				
			|||||||
@ -40,6 +40,8 @@ export const formatDataResponse = (hits) => {
 | 
				
			|||||||
    newData.tier = hit._source.tier;
 | 
					    newData.tier = hit._source.tier;
 | 
				
			||||||
    newData.owner = hit._source.owner;
 | 
					    newData.owner = hit._source.owner;
 | 
				
			||||||
    newData.highlight = hit.highlight;
 | 
					    newData.highlight = hit.highlight;
 | 
				
			||||||
 | 
					    newData.entityType = hit._source.entity_type;
 | 
				
			||||||
 | 
					    newData.changeDescriptions = hit._source.change_descriptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return newData;
 | 
					    return newData;
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
				
			|||||||
@ -14,19 +14,21 @@
 | 
				
			|||||||
import classNames from 'classnames';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
import { isEmpty, isUndefined } from 'lodash';
 | 
					import { isEmpty, isUndefined } from 'lodash';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  RecentlySearchData,
 | 
					  RecentlySearched,
 | 
				
			||||||
 | 
					  RecentlySearchedData,
 | 
				
			||||||
  RecentlyViewed,
 | 
					  RecentlyViewed,
 | 
				
			||||||
  RecentlyViewedData,
 | 
					  RecentlyViewedData,
 | 
				
			||||||
  SearchData,
 | 
					 | 
				
			||||||
} from 'Models';
 | 
					} from 'Models';
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import { reactLocalStorage } from 'reactjs-localstorage';
 | 
					import { reactLocalStorage } from 'reactjs-localstorage';
 | 
				
			||||||
import AppState from '../AppState';
 | 
					import AppState from '../AppState';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  LOCALSTORAGE_RECENTLY_SEARCH,
 | 
					  LOCALSTORAGE_RECENTLY_SEARCHED,
 | 
				
			||||||
  LOCALSTORAGE_RECENTLY_VIEWED,
 | 
					  LOCALSTORAGE_RECENTLY_VIEWED,
 | 
				
			||||||
  TITLE_FOR_NON_OWNER_ACTION,
 | 
					  TITLE_FOR_NON_OWNER_ACTION,
 | 
				
			||||||
} from '../constants/constants';
 | 
					} from '../constants/constants';
 | 
				
			||||||
 | 
					import { Ownership } from '../enums/mydata.enum';
 | 
				
			||||||
 | 
					import { User } from '../generated/entity/teams/user';
 | 
				
			||||||
import { UserTeam } from '../interface/team.interface';
 | 
					import { UserTeam } from '../interface/team.interface';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const arraySorterByKey = (
 | 
					export const arraySorterByKey = (
 | 
				
			||||||
@ -152,11 +154,51 @@ export const getCountBadge = (
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addToRecentSearch = (searchTerm: string): void => {
 | 
					export const getRecentlyViewedData = (): Array<RecentlyViewedData> => {
 | 
				
			||||||
 | 
					  const recentlyViewed: RecentlyViewed = reactLocalStorage.getObject(
 | 
				
			||||||
 | 
					    LOCALSTORAGE_RECENTLY_VIEWED
 | 
				
			||||||
 | 
					  ) as RecentlyViewed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (recentlyViewed?.data) {
 | 
				
			||||||
 | 
					    return recentlyViewed.data;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return [];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getRecentlySearchedData = (): Array<RecentlySearchedData> => {
 | 
				
			||||||
 | 
					  const recentlySearch: RecentlySearched = reactLocalStorage.getObject(
 | 
				
			||||||
 | 
					    LOCALSTORAGE_RECENTLY_SEARCHED
 | 
				
			||||||
 | 
					  ) as RecentlySearched;
 | 
				
			||||||
 | 
					  if (recentlySearch?.data) {
 | 
				
			||||||
 | 
					    return recentlySearch.data;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return [];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const setRecentlyViewedData = (
 | 
				
			||||||
 | 
					  recentData: Array<RecentlyViewedData>
 | 
				
			||||||
 | 
					): void => {
 | 
				
			||||||
 | 
					  reactLocalStorage.setObject(LOCALSTORAGE_RECENTLY_VIEWED, {
 | 
				
			||||||
 | 
					    data: recentData,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const setRecentlySearchedData = (
 | 
				
			||||||
 | 
					  recentData: Array<RecentlySearchedData>
 | 
				
			||||||
 | 
					): void => {
 | 
				
			||||||
 | 
					  reactLocalStorage.setObject(LOCALSTORAGE_RECENTLY_SEARCHED, {
 | 
				
			||||||
 | 
					    data: recentData,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const addToRecentSearched = (searchTerm: string): void => {
 | 
				
			||||||
  const searchData = { term: searchTerm, timestamp: Date.now() };
 | 
					  const searchData = { term: searchTerm, timestamp: Date.now() };
 | 
				
			||||||
  let recentlySearch: SearchData = reactLocalStorage.getObject(
 | 
					  const recentlySearch: RecentlySearched = reactLocalStorage.getObject(
 | 
				
			||||||
    LOCALSTORAGE_RECENTLY_SEARCH
 | 
					    LOCALSTORAGE_RECENTLY_SEARCHED
 | 
				
			||||||
  ) as SearchData;
 | 
					  ) as RecentlySearched;
 | 
				
			||||||
 | 
					  let arrSearchedData: RecentlySearched['data'] = [];
 | 
				
			||||||
  if (recentlySearch?.data) {
 | 
					  if (recentlySearch?.data) {
 | 
				
			||||||
    const arrData = recentlySearch.data
 | 
					    const arrData = recentlySearch.data
 | 
				
			||||||
      // search term is case-insensetive so we should also take care of it.
 | 
					      // search term is case-insensetive so we should also take care of it.
 | 
				
			||||||
@ -164,8 +206,8 @@ export const addToRecentSearch = (searchTerm: string): void => {
 | 
				
			|||||||
      .filter((item) => item.term !== searchData.term)
 | 
					      .filter((item) => item.term !== searchData.term)
 | 
				
			||||||
      .sort(
 | 
					      .sort(
 | 
				
			||||||
        arraySorterByKey('timestamp', true) as (
 | 
					        arraySorterByKey('timestamp', true) as (
 | 
				
			||||||
          a: RecentlySearchData,
 | 
					          a: RecentlySearchedData,
 | 
				
			||||||
          b: RecentlySearchData
 | 
					          b: RecentlySearchedData
 | 
				
			||||||
        ) => number
 | 
					        ) => number
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    arrData.unshift(searchData);
 | 
					    arrData.unshift(searchData);
 | 
				
			||||||
@ -173,13 +215,11 @@ export const addToRecentSearch = (searchTerm: string): void => {
 | 
				
			|||||||
    if (arrData.length > 5) {
 | 
					    if (arrData.length > 5) {
 | 
				
			||||||
      arrData.pop();
 | 
					      arrData.pop();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    recentlySearch.data = arrData;
 | 
					    arrSearchedData = arrData;
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    recentlySearch = {
 | 
					    arrSearchedData = [searchData];
 | 
				
			||||||
      data: [searchData],
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  reactLocalStorage.setObject(LOCALSTORAGE_RECENTLY_SEARCH, recentlySearch);
 | 
					  setRecentlySearchedData(arrSearchedData);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addToRecentViewed = (eData: RecentlyViewedData): void => {
 | 
					export const addToRecentViewed = (eData: RecentlyViewedData): void => {
 | 
				
			||||||
@ -210,37 +250,6 @@ export const addToRecentViewed = (eData: RecentlyViewedData): void => {
 | 
				
			|||||||
  reactLocalStorage.setObject(LOCALSTORAGE_RECENTLY_VIEWED, recentlyViewed);
 | 
					  reactLocalStorage.setObject(LOCALSTORAGE_RECENTLY_VIEWED, recentlyViewed);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getRecentlyViewedData = (): Array<RecentlyViewedData> => {
 | 
					 | 
				
			||||||
  const recentlyViewed: RecentlyViewed = reactLocalStorage.getObject(
 | 
					 | 
				
			||||||
    LOCALSTORAGE_RECENTLY_VIEWED
 | 
					 | 
				
			||||||
  ) as RecentlyViewed;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (recentlyViewed?.data) {
 | 
					 | 
				
			||||||
    return recentlyViewed.data;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return [];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getRecentlySearchData = (): Array<RecentlySearchData> => {
 | 
					 | 
				
			||||||
  const recentlySearch: SearchData = reactLocalStorage.getObject(
 | 
					 | 
				
			||||||
    LOCALSTORAGE_RECENTLY_SEARCH
 | 
					 | 
				
			||||||
  ) as SearchData;
 | 
					 | 
				
			||||||
  if (recentlySearch?.data) {
 | 
					 | 
				
			||||||
    return recentlySearch.data;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return [];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const setRecentlyViewedData = (
 | 
					 | 
				
			||||||
  recentData: Array<RecentlyViewedData>
 | 
					 | 
				
			||||||
): void => {
 | 
					 | 
				
			||||||
  reactLocalStorage.setObject(LOCALSTORAGE_RECENTLY_VIEWED, {
 | 
					 | 
				
			||||||
    data: recentData,
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getHtmlForNonAdminAction = (isClaimOwner: boolean) => {
 | 
					export const getHtmlForNonAdminAction = (isClaimOwner: boolean) => {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
@ -249,3 +258,18 @@ export const getHtmlForNonAdminAction = (isClaimOwner: boolean) => {
 | 
				
			|||||||
    </>
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getOwnerIds = (
 | 
				
			||||||
 | 
					  filter: Ownership,
 | 
				
			||||||
 | 
					  userDetails: User
 | 
				
			||||||
 | 
					): Array<string> => {
 | 
				
			||||||
 | 
					  if (filter === Ownership.OWNER && userDetails.teams) {
 | 
				
			||||||
 | 
					    const userTeams = !isEmpty(userDetails)
 | 
				
			||||||
 | 
					      ? userDetails.teams.map((team) => team.id)
 | 
				
			||||||
 | 
					      : [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return [...userTeams, getCurrentUserId()];
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return [getCurrentUserId()];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -189,7 +189,10 @@ export const summaryFormatter = (v: FieldChange) => {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getSummary = (changeDescription: ChangeDescription) => {
 | 
					export const getSummary = (
 | 
				
			||||||
 | 
					  changeDescription: ChangeDescription,
 | 
				
			||||||
 | 
					  isPrefix = false
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
  const fieldsAdded = [...(changeDescription?.fieldsAdded || [])];
 | 
					  const fieldsAdded = [...(changeDescription?.fieldsAdded || [])];
 | 
				
			||||||
  const fieldsDeleted = [...(changeDescription?.fieldsDeleted || [])];
 | 
					  const fieldsDeleted = [...(changeDescription?.fieldsDeleted || [])];
 | 
				
			||||||
  const fieldsUpdated = [...(changeDescription?.fieldsUpdated || [])];
 | 
					  const fieldsUpdated = [...(changeDescription?.fieldsUpdated || [])];
 | 
				
			||||||
@ -198,17 +201,23 @@ export const getSummary = (changeDescription: ChangeDescription) => {
 | 
				
			|||||||
    <Fragment>
 | 
					    <Fragment>
 | 
				
			||||||
      {fieldsAdded?.length > 0 ? (
 | 
					      {fieldsAdded?.length > 0 ? (
 | 
				
			||||||
        <p className="tw-mb-2">
 | 
					        <p className="tw-mb-2">
 | 
				
			||||||
          {fieldsAdded?.map(summaryFormatter).join(', ')} has been added
 | 
					          {`${isPrefix ? '+ Added' : ''} ${fieldsAdded
 | 
				
			||||||
 | 
					            ?.map(summaryFormatter)
 | 
				
			||||||
 | 
					            .join(', ')} ${!isPrefix ? `has been added` : ''}`}{' '}
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
      ) : null}
 | 
					      ) : null}
 | 
				
			||||||
      {fieldsUpdated?.length ? (
 | 
					      {fieldsUpdated?.length ? (
 | 
				
			||||||
        <p className="tw-mb-2">
 | 
					        <p className="tw-mb-2">
 | 
				
			||||||
          {fieldsUpdated?.map(summaryFormatter).join(', ')} has been updated
 | 
					          {`${isPrefix ? 'Edited' : ''} ${fieldsUpdated
 | 
				
			||||||
 | 
					            ?.map(summaryFormatter)
 | 
				
			||||||
 | 
					            .join(', ')} ${!isPrefix ? `has been updated` : ''}`}{' '}
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
      ) : null}
 | 
					      ) : null}
 | 
				
			||||||
      {fieldsDeleted?.length ? (
 | 
					      {fieldsDeleted?.length ? (
 | 
				
			||||||
        <p className="tw-mb-2">
 | 
					        <p className="tw-mb-2">
 | 
				
			||||||
          {fieldsDeleted?.map(summaryFormatter).join(', ')} has been deleted
 | 
					          {`${isPrefix ? '- Removed' : ''} ${fieldsDeleted
 | 
				
			||||||
 | 
					            ?.map(summaryFormatter)
 | 
				
			||||||
 | 
					            .join(', ')} ${!isPrefix ? `has been Deleted` : ''}`}{' '}
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
      ) : null}
 | 
					      ) : null}
 | 
				
			||||||
    </Fragment>
 | 
					    </Fragment>
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Copyright 2021 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 { Ownership } from '../enums/mydata.enum';
 | 
				
			||||||
 | 
					import { User } from '../generated/entity/teams/user';
 | 
				
			||||||
 | 
					import { getOwnerIds } from './CommonUtils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getMyDataFilters = (
 | 
				
			||||||
 | 
					  filter: Ownership,
 | 
				
			||||||
 | 
					  userDetails: User
 | 
				
			||||||
 | 
					): string => {
 | 
				
			||||||
 | 
					  return `(${getOwnerIds(filter, userDetails)
 | 
				
			||||||
 | 
					    .map((id) => `${filter}:${id}`)
 | 
				
			||||||
 | 
					    .join(' OR ')})`;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -10,6 +10,7 @@
 | 
				
			|||||||
 *  See the License for the specific language governing permissions and
 | 
					 *  See the License for the specific language governing permissions and
 | 
				
			||||||
 *  limitations under the License.
 | 
					 *  limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					import moment from 'moment';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const msPerSecond = 1000;
 | 
					const msPerSecond = 1000;
 | 
				
			||||||
const msPerMinute = 60 * msPerSecond;
 | 
					const msPerMinute = 60 * msPerSecond;
 | 
				
			||||||
@ -87,3 +88,18 @@ export const getRelativeTime = (timestamp: number): string => {
 | 
				
			|||||||
export const getRelativeDay = (timestamp: number): string => {
 | 
					export const getRelativeDay = (timestamp: number): string => {
 | 
				
			||||||
  return getRelativeDayDifference(Date.now(), timestamp);
 | 
					  return getRelativeDayDifference(Date.now(), timestamp);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getRelativeDateByTimeStamp = (timeStamp: number): string => {
 | 
				
			||||||
 | 
					  return moment(timeStamp).calendar(null, {
 | 
				
			||||||
 | 
					    sameDay: '[Today]',
 | 
				
			||||||
 | 
					    nextDay: 'DD MMMM YYYY',
 | 
				
			||||||
 | 
					    nextWeek: 'DD MMMM YYYY',
 | 
				
			||||||
 | 
					    lastDay: '[Yesterday]',
 | 
				
			||||||
 | 
					    lastWeek: 'DD MMMM YYYY',
 | 
				
			||||||
 | 
					    sameElse: 'DD MMMM YYYY',
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getTimeByTimeStamp = (timeStamp: number): string => {
 | 
				
			||||||
 | 
					  return moment(timeStamp, 'x').format('hh:mm A');
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -125,7 +125,7 @@ module.exports = {
 | 
				
			|||||||
        120: '30rem',
 | 
					        120: '30rem',
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      minWidth: {
 | 
					      minWidth: {
 | 
				
			||||||
        badgeCount: '24px',
 | 
					        badgeCount: '30px',
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      maxHeight: {
 | 
					      maxHeight: {
 | 
				
			||||||
        32: '8rem',
 | 
					        32: '8rem',
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user