mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-11 07:16:38 +00:00
feat(ui): localization for utils and models (#9265)
This commit is contained in:
parent
0eb49c6100
commit
0c7bf13901
@ -15,16 +15,14 @@ import { Form, Input, Modal, Space } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { observer } from 'mobx-react';
|
||||
import React, { FC, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import AppState from '../../../AppState';
|
||||
import { postThread } from '../../../axiosAPIs/feedsAPI';
|
||||
import {
|
||||
CreateThread,
|
||||
ThreadType,
|
||||
} from '../../../generated/api/feed/createThread';
|
||||
import {
|
||||
announcementInvalidStartTime,
|
||||
validateMessages,
|
||||
} from '../../../utils/AnnouncementsUtils';
|
||||
import { validateMessages } from '../../../utils/AnnouncementsUtils';
|
||||
import { getEntityFeedLink } from '../../../utils/EntityUtils';
|
||||
import { getTimeZone, getUTCDateTime } from '../../../utils/TimeUtils';
|
||||
import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils';
|
||||
@ -57,11 +55,13 @@ const AddAnnouncementModal: FC<Props> = ({
|
||||
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleCreateAnnouncement = async () => {
|
||||
const startTime = Math.floor(getUTCDateTime(startDate) / 1000);
|
||||
const endTime = Math.floor(getUTCDateTime(endDate) / 1000);
|
||||
if (startTime >= endTime) {
|
||||
showErrorToast(announcementInvalidStartTime);
|
||||
showErrorToast(t('message.announcement-invalid-start-time'));
|
||||
} else {
|
||||
const announcementData: CreateThread = {
|
||||
from: currentUser?.name as string,
|
||||
@ -78,7 +78,7 @@ const AddAnnouncementModal: FC<Props> = ({
|
||||
setIsLoading(true);
|
||||
const data = await postThread(announcementData);
|
||||
if (data) {
|
||||
showSuccessToast('Announcement created successfully!');
|
||||
showSuccessToast(t('message.announcement-created-successfully'));
|
||||
}
|
||||
onCancel();
|
||||
} catch (error) {
|
||||
@ -103,7 +103,7 @@ const AddAnnouncementModal: FC<Props> = ({
|
||||
htmlType: 'submit',
|
||||
}}
|
||||
okText="Submit"
|
||||
title="Make an announcement"
|
||||
title={t('label.make-an-announcement')}
|
||||
visible={open}
|
||||
width={620}
|
||||
onCancel={onCancel}>
|
||||
@ -114,7 +114,7 @@ const AddAnnouncementModal: FC<Props> = ({
|
||||
validateMessages={validateMessages}
|
||||
onFinish={handleCreateAnnouncement}>
|
||||
<Form.Item
|
||||
label="Title:"
|
||||
label={`${t('label.title')}:`}
|
||||
messageVariables={{ fieldName: 'title' }}
|
||||
name="title"
|
||||
rules={[
|
||||
@ -125,7 +125,7 @@ const AddAnnouncementModal: FC<Props> = ({
|
||||
},
|
||||
]}>
|
||||
<Input
|
||||
placeholder="Announcement title"
|
||||
placeholder={t('label.announcement-title')}
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
@ -133,7 +133,9 @@ const AddAnnouncementModal: FC<Props> = ({
|
||||
</Form.Item>
|
||||
<Space className="announcement-date-space" size={16}>
|
||||
<Form.Item
|
||||
label={`Start Date: (${getTimeZone()})`}
|
||||
label={t('label.start-date-time-zone', {
|
||||
timeZone: getTimeZone(),
|
||||
})}
|
||||
messageVariables={{ fieldName: 'startDate' }}
|
||||
name="startDate"
|
||||
rules={[
|
||||
@ -148,7 +150,9 @@ const AddAnnouncementModal: FC<Props> = ({
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={`End Date: (${getTimeZone()})`}
|
||||
label={t('label.end-date-time-zone', {
|
||||
timeZone: getTimeZone(),
|
||||
})}
|
||||
messageVariables={{ fieldName: 'endtDate' }}
|
||||
name="endtDate"
|
||||
rules={[
|
||||
@ -163,10 +167,10 @@ const AddAnnouncementModal: FC<Props> = ({
|
||||
/>
|
||||
</Form.Item>
|
||||
</Space>
|
||||
<Form.Item label="Description:" name="description">
|
||||
<Form.Item label={`${t('label.description')}:`} name="description">
|
||||
<RichTextEditor
|
||||
initialValue={description}
|
||||
placeHolder="write your announcement"
|
||||
placeHolder={t('label.write-your-announcement-lowercase')}
|
||||
onTextChange={(value) => setDescription(value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@ -14,11 +14,9 @@
|
||||
import { Form, Input, Modal, Space } from 'antd';
|
||||
import { observer } from 'mobx-react';
|
||||
import React, { FC, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AnnouncementDetails } from '../../../generated/entity/feed/thread';
|
||||
import {
|
||||
announcementInvalidStartTime,
|
||||
validateMessages,
|
||||
} from '../../../utils/AnnouncementsUtils';
|
||||
import { validateMessages } from '../../../utils/AnnouncementsUtils';
|
||||
import {
|
||||
getLocaleDateFromTimeStamp,
|
||||
getTimeZone,
|
||||
@ -53,12 +51,13 @@ const EditAnnouncementModal: FC<Props> = ({
|
||||
const [description, setDescription] = useState<string>(
|
||||
announcement.description || ''
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleConfirm = () => {
|
||||
const startTime = Math.floor(getUTCDateTime(startDate) / 1000);
|
||||
const endTime = Math.floor(getUTCDateTime(endDate) / 1000);
|
||||
if (startTime >= endTime) {
|
||||
showErrorToast(announcementInvalidStartTime);
|
||||
showErrorToast(t('message.announcement-invalid-start-time'));
|
||||
} else {
|
||||
const updatedAnnouncement = {
|
||||
...announcement,
|
||||
@ -82,8 +81,8 @@ const EditAnnouncementModal: FC<Props> = ({
|
||||
type: 'primary',
|
||||
htmlType: 'submit',
|
||||
}}
|
||||
okText="Save"
|
||||
title="Edit an announcement"
|
||||
okText={t('label.save')}
|
||||
title={t('label.edit-an-announcement')}
|
||||
visible={open}
|
||||
width={620}
|
||||
onCancel={onCancel}>
|
||||
@ -95,7 +94,7 @@ const EditAnnouncementModal: FC<Props> = ({
|
||||
validateMessages={validateMessages}
|
||||
onFinish={handleConfirm}>
|
||||
<Form.Item
|
||||
label="Title:"
|
||||
label={`${t('label.title')}:`}
|
||||
messageVariables={{ fieldName: 'title' }}
|
||||
name="title"
|
||||
rules={[
|
||||
@ -106,7 +105,7 @@ const EditAnnouncementModal: FC<Props> = ({
|
||||
},
|
||||
]}>
|
||||
<Input
|
||||
placeholder="Announcement title"
|
||||
placeholder={t('label.announcement-title')}
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
@ -114,7 +113,9 @@ const EditAnnouncementModal: FC<Props> = ({
|
||||
</Form.Item>
|
||||
<Space className="announcement-date-space" size={16}>
|
||||
<Form.Item
|
||||
label={`Start Date: (${getTimeZone()})`}
|
||||
label={t('label.start-date-time-zone', {
|
||||
timeZone: getTimeZone(),
|
||||
})}
|
||||
messageVariables={{ fieldName: 'startDate' }}
|
||||
name="startDate"
|
||||
rules={[
|
||||
@ -129,7 +130,9 @@ const EditAnnouncementModal: FC<Props> = ({
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={`End Date: (${getTimeZone()})`}
|
||||
label={t('label.end-date-time-zone', {
|
||||
timeZone: getTimeZone(),
|
||||
})}
|
||||
messageVariables={{ fieldName: 'endDate' }}
|
||||
name="endDate"
|
||||
rules={[
|
||||
@ -144,10 +147,10 @@ const EditAnnouncementModal: FC<Props> = ({
|
||||
/>
|
||||
</Form.Item>
|
||||
</Space>
|
||||
<Form.Item label="Description:" name="description">
|
||||
<Form.Item label={`${t('label.description')}:`} name="description">
|
||||
<RichTextEditor
|
||||
initialValue={description}
|
||||
placeHolder="write your announcement"
|
||||
placeHolder={t('label.write-your-announcement-lowercase')}
|
||||
onTextChange={(value) => setDescription(value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@ -471,6 +471,27 @@
|
||||
"retention-size": "retention-size",
|
||||
"clean-up-policies": "clean-up policies",
|
||||
"maximum-size": "maximum size",
|
||||
"openmetadata": "OpenMetadata",
|
||||
"activity-feeds": "Activity Feeds",
|
||||
"search": "Search",
|
||||
"enter": "Enter",
|
||||
"profiler": "Profiler",
|
||||
"data-profiler": "Data Profiler",
|
||||
"starting": "Starting",
|
||||
"idle": "Idle",
|
||||
"completed": "Completed",
|
||||
"active-with-error": "Active with error",
|
||||
"retry": "Retry",
|
||||
"claim-ownership-in-manage": "Claim ownership in Manage",
|
||||
"deactivated": "Deactivated",
|
||||
"username": "Username",
|
||||
"make-an-announcement": "Make an announcement",
|
||||
"announcement-title": "Announcement title",
|
||||
"start-date-time-zone": "Start Date: ({{timeZone}})",
|
||||
"end-date-time-zone": "End Date: ({{timeZone}})",
|
||||
"write-your-announcement-lowercase": "write your announcement",
|
||||
"title": "Title",
|
||||
"edit-an-announcement": "Edit an announcement",
|
||||
"no-of-test": " No. of Test",
|
||||
"test-suite": "Test Suite",
|
||||
"enter-entity": "Enter {{entity}}",
|
||||
@ -577,7 +598,24 @@
|
||||
"entity-owned-by-name": "This Entity is Owned by {{entityOwner}}",
|
||||
"and-followed-owned-by-name": "and followed team owned by {{userName}}",
|
||||
"field-text-is-invalid": "{{fieldText}} is invalid.",
|
||||
"delete-team-message": "Any teams under \"{{teamName}}\" will be {{deleteType}} deleted as well."
|
||||
"delete-team-message": "Any teams under \"{{teamName}}\" will be {{deleteType}} deleted as well.",
|
||||
"tour-step-discover-all-assets-at-one-place": "Discover all your data assets in a single place with <0>{{text}}</0>, a centralized metadata store. Collaborate with your team and get a holistic picture of the data in your organization.",
|
||||
"tour-step-activity-feed": "<0>{{text}}</0> help you understand how the data is changing in your organization.",
|
||||
"tour-step-search-for-matching-dataset": "Search for matching data assets by \"name\", \"description\", \"column name\", and so on from the <0>{{text}}</0> box.",
|
||||
"tour-step-type-search-term": "In the search box, type <0>\"{{text}}\"</0>. Hit <0>{{enterText}}.</0>",
|
||||
"tour-step-explore-summary-asset": "From the <0>\"{{text}}\"</0> page, view a summary of each asset, including: title, description, owner, tier (importance), usage, and location.",
|
||||
"tour-step-click-on-link-to-view-more": "Click on the <0>title of the asset</0> to view more details.",
|
||||
"tour-step-get-to-know-table-schema": "Get to know the table <0>Schema</0>, including column names and data types as well as column descriptions and tags. You can even view metadata for complex types such as structs.",
|
||||
"tour-step-click-on-entity-tab": "Click on the <0>\"{{text}}\"</0> tab.",
|
||||
"tour-step-look-at-sample-data": "Take a look at the <0>{{text}}</0> to get a feel for what the table contains and how you might use it.",
|
||||
"tour-step-trace-path-across-tables": " With <0>{{text}}</0>, trace the path of data across tables, pipelines, & dashboards.",
|
||||
"tour-step-discover-data-assets-with-data-profile": "Discover assets with the <0>{{text}}</0>. Get to know the table usage stats, check for null values and duplicates, and understand the column data distributions.",
|
||||
"lineage-data-is-not-available-for-deleted-entities": "Lineage data is not available for deleted entities.",
|
||||
"remove-edge-between-source-and-target": "Are you sure you want to remove the edge between \"{{sourceDisplayName}} and {{targetDisplayName}}\"?.",
|
||||
"announcement-invalid-start-time": "Announcement start time must be earlier than the end time",
|
||||
"permanently-delete-metadata-and-dependents": "Permanently deleting this {{entityName}} will remove its metadata, as well as the metadata of {{dependents}} from OpenMetadata permanently.",
|
||||
"permanently-delete-metadata": "Permanently deleting this {{entityName}} will remove its metadata from OpenMetadata permanently.",
|
||||
"announcement-created-successfully": "Announcement created successfully!"
|
||||
},
|
||||
"server": {
|
||||
"you-have-not-action-anything-yet": "You have not {{action}} anything yet.",
|
||||
|
||||
@ -82,3 +82,10 @@ jest.mock('react-i18next', () => ({
|
||||
}),
|
||||
t: (key) => key,
|
||||
}));
|
||||
|
||||
/**
|
||||
* mock i18next
|
||||
*/
|
||||
jest.mock('i18next', () => ({
|
||||
t: jest.fn().mockImplementation((key) => key),
|
||||
}));
|
||||
|
||||
@ -20,6 +20,3 @@ export const isActiveAnnouncement = (startTime: number, endTime: number) => {
|
||||
|
||||
return currentTime > startTime && currentTime < endTime;
|
||||
};
|
||||
|
||||
export const announcementInvalidStartTime =
|
||||
'Announcement start time must be earlier than the end time';
|
||||
|
||||
@ -16,7 +16,7 @@ import { Popover, Space, Tag, Typography } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import { AxiosError } from 'axios';
|
||||
import classNames from 'classnames';
|
||||
import i18n from 'i18next';
|
||||
import { t } from 'i18next';
|
||||
import {
|
||||
capitalize,
|
||||
isEmpty,
|
||||
@ -37,6 +37,7 @@ import {
|
||||
RecentlyViewedData,
|
||||
} from 'Models';
|
||||
import React from 'react';
|
||||
import { Trans } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { reactLocalStorage } from 'reactjs-localstorage';
|
||||
import AppState from '../AppState';
|
||||
@ -536,7 +537,7 @@ export const prepareLabel = (type: string, fqn: string, withQuotes = true) => {
|
||||
*/
|
||||
export const getEntityPlaceHolder = (value: string, isDeleted?: boolean) => {
|
||||
if (isDeleted) {
|
||||
return `${value} (Deactivated)`;
|
||||
return `${value} (${t('label.deactivated')})`;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
@ -586,13 +587,14 @@ export const getEntityId = (
|
||||
|
||||
export const getEntityDeleteMessage = (entity: string, dependents: string) => {
|
||||
if (dependents) {
|
||||
return `Permanently deleting this ${getTitleCase(
|
||||
entity
|
||||
)} will remove its metadata, as well as the metadata of ${dependents} from OpenMetadata permanently.`;
|
||||
return t('message.permanently-delete-metadata-and-dependents', {
|
||||
entityName: getTitleCase(entity),
|
||||
dependents,
|
||||
});
|
||||
} else {
|
||||
return `Permanently deleting this ${getTitleCase(
|
||||
entity
|
||||
)} will remove its metadata from OpenMetadata permanently.`;
|
||||
return t('message.permanently-delete-metadata-and-dependents', {
|
||||
entityName: getTitleCase(entity),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -731,7 +733,7 @@ export const getHostNameFromURL = (url: string) => {
|
||||
|
||||
export const commonUserDetailColumns: ColumnsType<User> = [
|
||||
{
|
||||
title: 'Username',
|
||||
title: t('label.username'),
|
||||
dataIndex: 'username',
|
||||
key: 'username',
|
||||
render: (_, record) => (
|
||||
@ -744,7 +746,7 @@ export const commonUserDetailColumns: ColumnsType<User> = [
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Teams',
|
||||
title: t('label.teams'),
|
||||
dataIndex: 'teams',
|
||||
key: 'teams',
|
||||
render: (_, record) => {
|
||||
@ -792,7 +794,7 @@ export const commonUserDetailColumns: ColumnsType<User> = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Roles',
|
||||
title: t('label.roles'),
|
||||
dataIndex: 'roles',
|
||||
key: 'roles',
|
||||
render: (_, record) => {
|
||||
@ -872,7 +874,7 @@ export const getEmptyPlaceholder = () => {
|
||||
return (
|
||||
<ErrorPlaceHolder size={SIZE.MEDIUM}>
|
||||
<Typography.Paragraph>
|
||||
{i18n.t('label.no-data-available')}
|
||||
{t('label.no-data-available')}
|
||||
</Typography.Paragraph>
|
||||
</ErrorPlaceHolder>
|
||||
);
|
||||
@ -952,6 +954,21 @@ export const sortTagsCaseInsensitive = (tags: TagLabel[]) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Transi18next = ({
|
||||
i18nKey,
|
||||
values,
|
||||
renderElement,
|
||||
...otherProps
|
||||
}: {
|
||||
i18nKey: string;
|
||||
values?: {};
|
||||
renderElement: JSX.Element | HTMLElement;
|
||||
}): JSX.Element => (
|
||||
<Trans i18nKey={i18nKey} values={values} {...otherProps}>
|
||||
{renderElement}
|
||||
</Trans>
|
||||
);
|
||||
|
||||
/**
|
||||
* It returns a link to the documentation for the given filter pattern type
|
||||
* @param {FilterPatternEnum} type - The type of filter pattern.
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import dagre from 'dagre';
|
||||
import { t } from 'i18next';
|
||||
import { isEmpty, isNil, isUndefined } from 'lodash';
|
||||
import { LeafNodes, LineagePos, LoadingNodeState, LoadingState } from 'Models';
|
||||
import React, { Fragment, MouseEvent as ReactMouseEvent } from 'react';
|
||||
@ -431,29 +432,12 @@ export const getDataLabel = (
|
||||
}
|
||||
};
|
||||
|
||||
export const getNoLineageDataPlaceholder = () => {
|
||||
return (
|
||||
<div className="tw-mt-4 tw-ml-4 tw-flex tw-justify-center tw-font-medium tw-items-center tw-border tw-border-main tw-rounded-md tw-p-8">
|
||||
<span>
|
||||
Lineage is currently supported for Airflow. To enable lineage collection
|
||||
from Airflow, please follow the documentation
|
||||
</span>
|
||||
<Link
|
||||
className="tw-ml-1"
|
||||
target="_blank"
|
||||
to={{
|
||||
pathname:
|
||||
'https://docs.open-metadata.org/openmetadata/connectors/pipeline/airflow/lineage-backend',
|
||||
}}>
|
||||
here.
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const getDeletedLineagePlaceholder = () => {
|
||||
return (
|
||||
<div className="tw-mt-4 tw-ml-4 tw-flex tw-justify-center tw-font-medium tw-items-center tw-border tw-border-main tw-rounded-md tw-p-8">
|
||||
<span>Lineage data is not available for deleted entities.</span>
|
||||
<span>
|
||||
{t('message.lineage-data-is-not-available-for-deleted-entities')}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -527,9 +511,10 @@ export const getModalBodyText = (selectedEdge: SelectedEdge) => {
|
||||
targetEntity = getPartialNameFromFQN(targetFQN || '', ['database']);
|
||||
}
|
||||
|
||||
return `Are you sure you want to remove the edge between "${
|
||||
source.displayName ? source.displayName : sourceEntity
|
||||
} and ${target.displayName ? target.displayName : targetEntity}"?`;
|
||||
return t('message.remove-edge-between-source-and-target', {
|
||||
sourceDisplayName: source.displayName ? source.displayName : sourceEntity,
|
||||
targetDisplayName: target.displayName ? target.displayName : targetEntity,
|
||||
});
|
||||
};
|
||||
|
||||
export const getUniqueFlowElements = (elements: CustomFlow[]) => {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { t } from 'i18next';
|
||||
import { Status } from '../generated/settings/eventPublisherJob';
|
||||
import { Icons } from './SvgUtils';
|
||||
|
||||
@ -37,19 +38,19 @@ export const getStatusResultBadgeIcon = (status: string) => {
|
||||
export const getEventPublisherStatusText = (status?: string) => {
|
||||
switch (status) {
|
||||
case Status.Starting:
|
||||
return 'Starting';
|
||||
return t('label.starting');
|
||||
case Status.Idle:
|
||||
return 'Idle';
|
||||
return t('label.idle');
|
||||
case Status.Completed:
|
||||
return 'Completed';
|
||||
return t('label.completed');
|
||||
case Status.Active:
|
||||
return 'Active';
|
||||
return t('label.active');
|
||||
|
||||
case Status.ActiveWithError:
|
||||
return 'Active with error';
|
||||
return t('label.active-with-error');
|
||||
|
||||
case Status.Retry:
|
||||
return 'Retry';
|
||||
return t('label.retry');
|
||||
|
||||
default:
|
||||
return status || '';
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
import antlr4 from 'antlr4';
|
||||
import { ParseTreeWalker } from 'antlr4/src/antlr4/tree';
|
||||
import i18next from 'i18next';
|
||||
import SplitListener from '../antlr/SplitListener';
|
||||
import FqnLexer from '../generated/antlr/FqnLexer';
|
||||
import FqnParser from '../generated/antlr/FqnParser';
|
||||
@ -45,7 +46,7 @@ export default class Fqn {
|
||||
static quoteName(name) {
|
||||
const matcher = /^(")([^"]+)(")$|^(.*)$/.exec(name);
|
||||
if (!matcher || matcher[0].length != name.length) {
|
||||
throw 'Invalid name ' + name;
|
||||
throw new Error(`${i18next.t('label.invalid-name')} ${name}`);
|
||||
}
|
||||
|
||||
// Name matches quoted string "sss".
|
||||
@ -63,6 +64,6 @@ export default class Fqn {
|
||||
return unquotedName.includes('.') ? '"' + name + '"' : unquotedName;
|
||||
}
|
||||
|
||||
throw 'Invalid name ' + name;
|
||||
throw new Error(`${i18next.t('label.invalid-name')} ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,8 +59,8 @@ describe('Test FQN', () => {
|
||||
expect('"a.b"').toStrictEqual(Fqn.quoteName('"a.b"')); // Leave existing valid quotes
|
||||
expect('a').toStrictEqual(Fqn.quoteName('"a"')); // Remove quotes when not needed
|
||||
|
||||
expect(() => Fqn.quoteName('"a')).toThrow('Invalid name "a'); // Error when ending quote is missing
|
||||
expect(() => Fqn.quoteName('a"')).toThrow('Invalid name a"'); // Error when beginning quote is missing
|
||||
expect(() => Fqn.quoteName('a"b')).toThrow('Invalid name a"b'); // Error when invalid quote is present in the middle of the string
|
||||
expect(() => Fqn.quoteName('"a')).toThrow('label.invalid-name "a'); // Error when ending quote is missing
|
||||
expect(() => Fqn.quoteName('a"')).toThrow('label.invalid-name a"'); // Error when beginning quote is missing
|
||||
expect(() => Fqn.quoteName('a"b')).toThrow('label.invalid-name a"b'); // Error when invalid quote is present in the middle of the string
|
||||
});
|
||||
});
|
||||
|
||||
@ -11,9 +11,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import i18next from 'i18next';
|
||||
import React from 'react';
|
||||
import AppState from '../AppState';
|
||||
import { CurrentTourPageType } from '../enums/tour.enum';
|
||||
import { Transi18next } from './CommonUtils';
|
||||
import { getCurrentDatasetTab } from './DatasetDetailsUtils';
|
||||
|
||||
export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
@ -21,10 +23,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Discover all your data assets in a single place with{' '}
|
||||
<strong>OpenMetadata</strong>, a centralized metadata store.
|
||||
Collaborate with your team and get a holistic picture of the data in
|
||||
your organization.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-discover-all-assets-at-one-place"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.openmetadata'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
stepInteraction: false,
|
||||
@ -33,8 +38,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
<strong>Activity Feeds</strong> help you understand how the data is
|
||||
changing in your organization.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-activity-feed"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.activity-feeds'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#feedData',
|
||||
@ -43,9 +53,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Search for matching data assets by "name",
|
||||
"description", "column name", and so on from the{' '}
|
||||
<strong>Search</strong> box.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-search-for-matching-dataset"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.search'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#searchBox',
|
||||
@ -56,8 +70,14 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
beforePrev: clearSearchTerm,
|
||||
content: () => (
|
||||
<p>
|
||||
In the search box, type <strong>"{value}"</strong>. Hit{' '}
|
||||
<strong>Enter.</strong>
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-type-search-term"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: value,
|
||||
enterText: i18next.t('label.enter'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
actionType: 'enter',
|
||||
@ -74,9 +94,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
},
|
||||
content: () => (
|
||||
<p>
|
||||
From the <strong>"Explore"</strong> page, view a summary of
|
||||
each asset, including: title, description, owner, tier (importance),
|
||||
usage, and location.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-explore-summary-asset"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.explore'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#tabledatacard0',
|
||||
@ -85,7 +109,10 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>title of the asset</strong> to view more details.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-click-on-link-to-view-more"
|
||||
renderElement={<strong />}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
actionType: 'click',
|
||||
@ -100,10 +127,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
},
|
||||
content: () => (
|
||||
<p>
|
||||
{' '}
|
||||
Get to know the table <strong>Schema</strong>, including column names
|
||||
and data types as well as column descriptions and tags. You can even
|
||||
view metadata for complex types such as structs.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-get-to-know-table-schema"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.schema'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
stepInteraction: false,
|
||||
@ -116,7 +146,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Sample Data"</strong> tab.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-click-on-entity-tab"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.sample-data'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#sampleData',
|
||||
@ -128,8 +164,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Take a look at the <strong>Sample Data</strong> to get a feel for what
|
||||
the table contains and how you might use it.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-look-at-sample-data"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.sample-data'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#sampleDataDetails',
|
||||
@ -145,7 +186,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Profiler"</strong> tab.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-click-on-entity-tab"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.profiler'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#profilerDataQuality',
|
||||
@ -153,9 +200,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
Discover assets with the <strong>Data Profiler</strong>. Get to know
|
||||
the table usage stats, check for null values and duplicates, and
|
||||
understand the column data distributions.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-discover-data-assets-with-data-profile"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.data-profiler'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
stepInteraction: false,
|
||||
@ -171,7 +222,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
<p>
|
||||
Click on the <strong>"Lineage"</strong> tab
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-click-on-entity-tab"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.lineage'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#lineage',
|
||||
@ -179,8 +236,13 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
{
|
||||
content: () => (
|
||||
<p>
|
||||
With <strong>Lineage</strong>, trace the path of data across tables,
|
||||
pipelines, & dashboards.
|
||||
<Transi18next
|
||||
i18nKey="message.tour-step-trace-path-across-tables"
|
||||
renderElement={<strong />}
|
||||
values={{
|
||||
text: i18next.t('label.lineage'),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
stepInteraction: false,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user