mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-01 02:56:10 +00:00
parent
0c12a55ebf
commit
6dbb1e578d
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1792 1792" fill="#37352f"><path d="M1408 928v320q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h704q14 0 23 9t9 23v64q0 14-9 23t-23 9h-704q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113v-320q0-14 9-23t23-9h64q14 0 23 9t9 23zm384-864v512q0 26-19 45t-45 19-45-19l-176-176-652 652q-10 10-23 10t-23-10l-114-114q-10-10-10-23t10-23l652-652-176-176q-19-19-19-45t19-45 45-19h512q26 0 45 19t19 45z"/></svg>
|
||||
|
After Width: | Height: | Size: 520 B |
@ -0,0 +1 @@
|
||||
<svg data-v-49ba913f="" width="80" height="75" viewBox="0 0 80 75" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="#F6C247" d="M63.196 48.5l2.126 26.188-24.585-11.316-25.364 10.696 1.72-25.563L0 29.013l27.775-7.464L40.135 0l14.262 23.331L80 28.688 63.196 48.5"></path><path d="M60.097 48.955l1.657 20.42-15.109-6.954a1.755 1.755 0 01-1.022-1.61 995.1 995.1 0 00.036-6.576c0-1.89-.65-3.128-1.379-3.753 4.523-.503 9.268-2.216 9.268-10.004 0-2.212-.786-4.021-2.087-5.438.21-.513.906-2.574-.202-5.365 0 0-1.7-.545-5.575 2.078a19.514 19.514 0 00-5.08-.683 19.49 19.49 0 00-5.082.683c-3.877-2.623-5.58-2.078-5.58-2.078-1.106 2.79-.409 4.852-.2 5.365-1.298 1.417-2.09 3.226-2.09 5.438 0 7.77 4.738 9.507 9.246 10.02-.58.506-1.104 1.399-1.289 2.709-1.156.52-4.096 1.414-5.907-1.685 0 0-.717-1.643-2.754-1.787 0 0-1.982-.026-.14 1.232 0 0 1.314.754 1.9 2.126 0 0 1.19 3.942 6.837 2.718.006.981.014 3.32.02 5.113a1.756 1.756 0 01-1.075 1.624l-15.336 6.468 1.452-21.584-.973-1.11-13.54-15.443 22.64-6.085 1.43-.384L40.399 6.562l12.103 19.805 1.51.316 20.051 4.195-14.085 16.61.12 1.467" fill="#DE852E"></path></g></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@ -59,6 +59,10 @@ export const fetchAuthorizerConfig: Function = (): Promise<AxiosResponse> => {
|
||||
return APIClient.get('/config/authorizer');
|
||||
};
|
||||
|
||||
export const fetchSandboxConfig = (): Promise<AxiosResponse> => {
|
||||
return APIClient.get('/config/sandbox');
|
||||
};
|
||||
|
||||
export const getSuggestions: Function = (
|
||||
queryString: string,
|
||||
searchIndex?: string
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 React, { CSSProperties, FunctionComponent, useState } from 'react';
|
||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||
import PopOver from '../common/popover/PopOver';
|
||||
|
||||
const GithubStarButton: FunctionComponent = () => {
|
||||
const [open, setOpen] = useState<boolean>(true);
|
||||
|
||||
const handleClick = (isOpen?: boolean) => {
|
||||
setOpen((pre) => (!isNil(isOpen) ? isOpen : !pre));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="tw-fixed tw-bottom-8 tw-right-8">
|
||||
<PopOver
|
||||
delay={100}
|
||||
html={
|
||||
<>
|
||||
<a
|
||||
className="link-text-grey tw-text-sm tw-font-medium"
|
||||
href="https://github.com/open-metadata/OpenMetadata"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank">
|
||||
<span className="tw-mr-1">Star us on Github</span>
|
||||
<SVGIcons
|
||||
alt="external-link"
|
||||
className="tw-align-middle"
|
||||
icon={Icons.EXTERNAL_LINK_GREY}
|
||||
width="12px"
|
||||
/>
|
||||
</a>
|
||||
</>
|
||||
}
|
||||
open={open}
|
||||
popperOptions={{
|
||||
modifiers: {
|
||||
addZIndex: {
|
||||
enabled: true,
|
||||
order: 810,
|
||||
// react-tippy has this dataObject that can be of any type
|
||||
fn: (data: { styles: CSSProperties }) => ({
|
||||
...data,
|
||||
styles: {
|
||||
...data.styles,
|
||||
zIndex: 9990,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
}}
|
||||
position="left"
|
||||
theme="light"
|
||||
trigger="click">
|
||||
<button
|
||||
className="tw-h-12 tw-w-12 tw-rounded-full tw-shadow-lg tw-cursor-pointer tw-bg-white"
|
||||
onClick={() => handleClick()}>
|
||||
<SVGIcons
|
||||
alt="gh-star"
|
||||
data-testid="gh-star"
|
||||
icon={Icons.GITHUB_STAR}
|
||||
width="30"
|
||||
/>
|
||||
</button>
|
||||
</PopOver>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GithubStarButton;
|
||||
@ -30,7 +30,8 @@ const PopOver: React.FC<PopOverProp> = ({
|
||||
trigger,
|
||||
theme = 'dark',
|
||||
sticky = false,
|
||||
}): JSX.Element => {
|
||||
...props
|
||||
}: PopOverProp): JSX.Element => {
|
||||
return (
|
||||
<Tooltip
|
||||
arrow={arrow}
|
||||
@ -43,7 +44,8 @@ const PopOver: React.FC<PopOverProp> = ({
|
||||
sticky={sticky}
|
||||
theme={theme}
|
||||
title={title || ''}
|
||||
trigger={trigger}>
|
||||
trigger={trigger}
|
||||
{...props}>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
@ -12,13 +12,14 @@
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
import { TooltipProps } from 'react-tippy';
|
||||
|
||||
export type Position = 'top' | 'left' | 'bottom' | 'right';
|
||||
export type Trigger = 'mouseenter' | 'focus' | 'click' | 'manual';
|
||||
export type Theme = 'dark' | 'light' | 'transparent';
|
||||
export type Size = 'small' | 'regular' | 'big';
|
||||
|
||||
export type PopOverProp = {
|
||||
export interface PopOverProp extends TooltipProps {
|
||||
html?: React.ReactElement;
|
||||
title?: string;
|
||||
arrow?: boolean;
|
||||
@ -31,4 +32,4 @@ export type PopOverProp = {
|
||||
delay?: number;
|
||||
hideDelay?: number;
|
||||
sticky?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
@ -59,6 +59,8 @@ const jsonData = {
|
||||
'fetch-ingestion-error': 'Error while fetching ingestion workflow!',
|
||||
'fetch-service-error': 'Error while fetching service details!',
|
||||
|
||||
'unexpected-server-response': 'Unexpected response from server!',
|
||||
|
||||
'update-chart-error': 'Error while updating charts!',
|
||||
'update-owner-error': 'Error while updating owner',
|
||||
'update-glossary-term-error': 'Error while updating glossary term!',
|
||||
@ -70,7 +72,6 @@ const jsonData = {
|
||||
'update-entity-unfollow-error': 'Error while unfollowing entity!',
|
||||
'update-ingestion-error': 'Error while updating ingestion workflow',
|
||||
'update-service-config-error': 'Error while updating ingestion workflow',
|
||||
'unexpected-server-response': 'Unexpected response from server!',
|
||||
},
|
||||
'api-success-messages': {
|
||||
'create-conversation': 'Conversation created successfully!',
|
||||
|
||||
@ -20,13 +20,14 @@ import {
|
||||
FormatedTableData,
|
||||
SearchResponse,
|
||||
} from 'Models';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { Fragment, useEffect, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import AppState from '../../AppState';
|
||||
import { getAirflowPipelines } from '../../axiosAPIs/airflowPipelineAPI';
|
||||
import { getFeedsWithFilter, postFeedById } from '../../axiosAPIs/feedsAPI';
|
||||
import { searchData } from '../../axiosAPIs/miscAPI';
|
||||
import { fetchSandboxConfig, searchData } from '../../axiosAPIs/miscAPI';
|
||||
import PageContainerV1 from '../../components/containers/PageContainerV1';
|
||||
import GithubStarButton from '../../components/GithubStarButton/GithubStarButton';
|
||||
import Loader from '../../components/Loader/Loader';
|
||||
import MyData from '../../components/MyData/MyData.component';
|
||||
import {
|
||||
@ -41,6 +42,7 @@ import {
|
||||
import { FeedFilter, Ownership } from '../../enums/mydata.enum';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
import useToastContext from '../../hooks/useToastContext';
|
||||
import jsonData from '../../jsons/en';
|
||||
import { formatDataResponse } from '../../utils/APIUtils';
|
||||
import { getEntityCountByType } from '../../utils/EntityUtils';
|
||||
import { deletePost, getUpdatedThread } from '../../utils/FeedUtils';
|
||||
@ -64,6 +66,7 @@ const MyDataPage = () => {
|
||||
const [feedFilter, setFeedFilter] = useState<FeedFilter>(FeedFilter.ALL);
|
||||
const [entityThread, setEntityThread] = useState<EntityThread[]>([]);
|
||||
const [isFeedLoading, setIsFeedLoading] = useState<boolean>(false);
|
||||
const [isSandbox, setIsSandbox] = useState<boolean>(false);
|
||||
const feedFilterHandler = (filter: FeedFilter) => {
|
||||
setFeedFilter(filter);
|
||||
};
|
||||
@ -219,7 +222,29 @@ const MyDataPage = () => {
|
||||
showToast({ variant: 'error', body: message ?? onErrorText });
|
||||
});
|
||||
};
|
||||
|
||||
const fetchOMDMode = () => {
|
||||
fetchSandboxConfig()
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
setIsSandbox(Boolean(res.data.sandboxModeEnabled));
|
||||
} else {
|
||||
throw '';
|
||||
}
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
showToast({
|
||||
variant: 'error',
|
||||
body:
|
||||
err.response?.data?.message ||
|
||||
jsonData['api-error-messages']['unexpected-server-response'],
|
||||
});
|
||||
setIsSandbox(false);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchOMDMode();
|
||||
fetchData(true);
|
||||
}, []);
|
||||
|
||||
@ -243,21 +268,24 @@ const MyDataPage = () => {
|
||||
!isUndefined(entityCounts) &&
|
||||
!isUndefined(ingestionCount) &&
|
||||
!isLoading ? (
|
||||
<MyData
|
||||
countServices={countServices}
|
||||
deletePostHandler={deletePostHandler}
|
||||
entityCounts={entityCounts}
|
||||
error={error}
|
||||
feedData={entityThread || []}
|
||||
feedFilter={feedFilter}
|
||||
feedFilterHandler={feedFilterHandler}
|
||||
followedData={followedData || []}
|
||||
ingestionCount={ingestionCount}
|
||||
isFeedLoading={isFeedLoading}
|
||||
ownedData={ownedData || []}
|
||||
postFeedHandler={postFeedHandler}
|
||||
searchResult={searchResult}
|
||||
/>
|
||||
<Fragment>
|
||||
<MyData
|
||||
countServices={countServices}
|
||||
deletePostHandler={deletePostHandler}
|
||||
entityCounts={entityCounts}
|
||||
error={error}
|
||||
feedData={entityThread || []}
|
||||
feedFilter={feedFilter}
|
||||
feedFilterHandler={feedFilterHandler}
|
||||
followedData={followedData || []}
|
||||
ingestionCount={ingestionCount}
|
||||
isFeedLoading={isFeedLoading}
|
||||
ownedData={ownedData || []}
|
||||
postFeedHandler={postFeedHandler}
|
||||
searchResult={searchResult}
|
||||
/>
|
||||
{isSandbox ? <GithubStarButton /> : null}
|
||||
</Fragment>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
|
||||
@ -11,10 +11,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { findByText, render } from '@testing-library/react';
|
||||
import { findByText, queryByText, render } from '@testing-library/react';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { fetchSandboxConfig } from '../../axiosAPIs/miscAPI';
|
||||
import MyDataPageComponent from './MyDataPage.component';
|
||||
|
||||
const mockAuth = {
|
||||
isAuthDisabled: true,
|
||||
};
|
||||
|
||||
const mockErrors = {
|
||||
sandboxMode: 'SandboxModeError',
|
||||
};
|
||||
|
||||
jest.mock('../../components/MyData/MyData.component', () => {
|
||||
return jest
|
||||
.fn()
|
||||
@ -34,6 +43,13 @@ jest.mock('../../axiosAPIs/miscAPI', () => ({
|
||||
},
|
||||
})
|
||||
),
|
||||
fetchSandboxConfig: jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
sandboxModeEnabled: false,
|
||||
},
|
||||
})
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/airflowPipelineAPI', () => ({
|
||||
@ -46,6 +62,16 @@ jest.mock('../../axiosAPIs/airflowPipelineAPI', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/feedsAPI', () => ({
|
||||
getFeedsWithFilter: jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
data: [],
|
||||
},
|
||||
})
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/ServiceUtils', () => ({
|
||||
getAllServices: jest.fn().mockImplementation(() => Promise.resolve(['test'])),
|
||||
getEntityCountByService: jest.fn().mockReturnValue({
|
||||
@ -56,9 +82,9 @@ jest.mock('../../utils/ServiceUtils', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
const mockAuth = {
|
||||
isAuthDisabled: true,
|
||||
};
|
||||
jest.mock('../../utils/CommonUtils', () => ({
|
||||
isSandboxOMD: jest.fn().mockReturnValue(true),
|
||||
}));
|
||||
|
||||
jest.mock('../../hooks/authHooks', () => ({
|
||||
useAuth: jest.fn(() => mockAuth),
|
||||
@ -86,12 +112,84 @@ jest.mock('../../components/MyData/MyData.component', () => {
|
||||
return jest.fn().mockImplementation(() => <p>MyData.component</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../components/GithubStarButton/GithubStarButton', () => {
|
||||
return jest.fn().mockImplementation(() => <p>GithubStarButton.component</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../components/common/Toast/Toast', () => {
|
||||
return jest.fn().mockImplementation(() => <p>GithubStarButton.component</p>);
|
||||
});
|
||||
|
||||
describe('Test MyData page component', () => {
|
||||
it('Component should render', async () => {
|
||||
const { container } = render(<MyDataPageComponent />);
|
||||
|
||||
const myData = await findByText(container, /MyData.component/i);
|
||||
|
||||
const githubStarButton = await queryByText(
|
||||
container,
|
||||
/GithubStarButton.component/i
|
||||
);
|
||||
|
||||
expect(myData).toBeInTheDocument();
|
||||
expect(githubStarButton).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Component should render in sandbox mode', async () => {
|
||||
(fetchSandboxConfig as jest.Mock).mockImplementationOnce(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
sandboxModeEnabled: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const { container } = render(<MyDataPageComponent />);
|
||||
const myData = await findByText(container, /MyData.component/i);
|
||||
|
||||
const githubStarButton = await findByText(
|
||||
container,
|
||||
/GithubStarButton.component/i
|
||||
);
|
||||
|
||||
expect(myData).toBeInTheDocument();
|
||||
expect(githubStarButton).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe('render Sad Paths', () => {
|
||||
it('show error message on failing of config/sandbox api', async () => {
|
||||
(fetchSandboxConfig as jest.Mock).mockImplementationOnce(() =>
|
||||
Promise.reject({
|
||||
response: { data: { message: mockErrors.sandboxMode } },
|
||||
})
|
||||
);
|
||||
|
||||
const { container } = render(<MyDataPageComponent />);
|
||||
const myData = await findByText(container, /MyData.component/i);
|
||||
|
||||
const githubStarButton = await queryByText(
|
||||
container,
|
||||
/GithubStarButton.component/i
|
||||
);
|
||||
|
||||
expect(myData).toBeInTheDocument();
|
||||
expect(githubStarButton).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('show error message on no data from config/sandbox api', async () => {
|
||||
(fetchSandboxConfig as jest.Mock).mockImplementationOnce(() =>
|
||||
Promise.resolve({})
|
||||
);
|
||||
|
||||
const { container } = render(<MyDataPageComponent />);
|
||||
const myData = await findByText(container, /MyData.component/i);
|
||||
|
||||
const githubStarButton = await queryByText(
|
||||
container,
|
||||
/GithubStarButton.component/i
|
||||
);
|
||||
|
||||
expect(myData).toBeInTheDocument();
|
||||
expect(githubStarButton).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -140,6 +140,11 @@
|
||||
@apply tw-text-primary-hover hover:tw-text-primary-hover focus:tw-text-primary-hover hover:tw-underline focus:tw-underline tw-cursor-pointer;
|
||||
}
|
||||
|
||||
a[href].link-text-grey,
|
||||
.link-text-grey {
|
||||
@apply tw-text-grey-body hover:tw-text-grey-body focus:tw-text-grey-body hover:tw-underline focus:tw-underline tw-cursor-pointer;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
@apply tw-bg-body-main;
|
||||
}
|
||||
|
||||
@ -45,9 +45,11 @@ import IconDoc from '../assets/svg/doc.svg';
|
||||
import IconEditBlack from '../assets/svg/edit-black.svg';
|
||||
import IconEditPrimary from '../assets/svg/edit-primary.svg';
|
||||
import IconError from '../assets/svg/error.svg';
|
||||
import IconExternalLinkGrey from '../assets/svg/external-link-grey.svg';
|
||||
import IconExternalLinkWhite from '../assets/svg/external-link-white.svg';
|
||||
import IconExternalLink from '../assets/svg/external-link.svg';
|
||||
import IconFitView from '../assets/svg/fitview.svg';
|
||||
import IconGithubStar from '../assets/svg/github-star.svg';
|
||||
import IconCheckCircle from '../assets/svg/ic-check-circle.svg';
|
||||
import IconDelete from '../assets/svg/ic-delete.svg';
|
||||
import IconDownArrow from '../assets/svg/ic-down-arrow.svg';
|
||||
@ -214,6 +216,7 @@ export const Icons = {
|
||||
SLACK_GREY: 'slack-grey',
|
||||
EXTERNAL_LINK: 'external-link',
|
||||
EXTERNAL_LINK_WHITE: 'external-link-white',
|
||||
EXTERNAL_LINK_GREY: 'external-link-grey',
|
||||
PROFILER: 'icon-profiler',
|
||||
PIPELINE: 'pipeline',
|
||||
PIPELINE_GREY: 'pipeline-grey',
|
||||
@ -261,6 +264,7 @@ export const Icons = {
|
||||
WEBHOOK: 'icon-webhook',
|
||||
WEBHOOK_GREY: 'icon-webhook-grey',
|
||||
WEBHOOK_PRIMARY: 'icon-webhook-primary',
|
||||
GITHUB_STAR: 'icon-github-star',
|
||||
};
|
||||
|
||||
const SVGIcons: FunctionComponent<Props> = ({
|
||||
@ -562,6 +566,10 @@ const SVGIcons: FunctionComponent<Props> = ({
|
||||
case Icons.EXTERNAL_LINK_WHITE:
|
||||
IconComponent = IconExternalLinkWhite;
|
||||
|
||||
break;
|
||||
case Icons.EXTERNAL_LINK_GREY:
|
||||
IconComponent = IconExternalLinkGrey;
|
||||
|
||||
break;
|
||||
case Icons.PROFILER:
|
||||
IconComponent = IconProfiler;
|
||||
@ -756,6 +764,10 @@ const SVGIcons: FunctionComponent<Props> = ({
|
||||
case Icons.WEBHOOK_PRIMARY:
|
||||
IconComponent = IconWebhookPrimary;
|
||||
|
||||
break;
|
||||
case Icons.GITHUB_STAR:
|
||||
IconComponent = IconGithubStar;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user