UI : Localization fix (#10183)

* Localization fix

* fix unit test issue

* changes as per comments

---------

Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
Co-authored-by: Sachin Chaurasiya <sachinchaurasiyachotey87@gmail.com>
This commit is contained in:
Ashish Gupta 2023-02-17 10:17:12 +04:00 committed by GitHub
parent 5b94f5ae70
commit 2ba6211b58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 142 additions and 61 deletions

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none"><path fill="#7147E8" stroke="#7147E8" stroke-width=".2" d="M11.278 2.166H9.955v-.592c0-.191-.21-.278-.4-.278H8.526C8.283.599 7.674.25 6.977.25a1.584 1.584 0 0 0-1.549 1.045h-1.01c-.19 0-.382.087-.382.278v.592H2.712a1.48 1.48 0 0 0-1.462 1.41v8.85c0 .767.696 1.324 1.462 1.324h8.566c.766 0 1.462-.557 1.462-1.323v-8.85a1.48 1.48 0 0 0-1.462-1.41Zm-6.546-.174h.957a.383.383 0 0 0 .331-.313 1.01 1.01 0 0 1 .958-.784.992.992 0 0 1 .94.784c.031.171.174.3.348.313h.992v1.393H4.732V1.992Zm7.312 10.435c0 .383-.383.627-.766.627H2.712c-.383 0-.766-.244-.766-.627v-8.85a.783.783 0 0 1 .766-.714h1.324v.887a.366.366 0 0 0 .383.331h5.135c.2.011.374-.133.4-.33v-.888h1.324c.4.007.73.315.766.713v8.85Z"/><path fill="#7147E8" stroke="#7147E8" stroke-width=".2" d="M5.663 9.525a.283.283 0 0 0-.396-.014l-.906.863-.382-.396a.283.283 0 0 0-.397-.014.297.297 0 0 0 0 .41l.58.595c.05.056.123.087.199.085a.283.283 0 0 0 .198-.085L5.663 9.92a.269.269 0 0 0 0-.396ZM10.243 10H7.368c-.138 0-.25.167-.25.374s.112.375.25.375h2.875c.138 0 .25-.168.25-.375S10.38 10 10.243 10ZM5.663 6.526a.283.283 0 0 0-.396-.014l-.906.863-.382-.396a.283.283 0 0 0-.397-.014.297.297 0 0 0 0 .41l.58.594c.05.057.123.088.199.085a.283.283 0 0 0 .198-.085l1.104-1.047a.269.269 0 0 0 0-.396ZM10.243 7H7.368c-.138 0-.25.168-.25.375s.112.375.25.375h2.875c.138 0 .25-.168.25-.375S10.38 7 10.243 7Z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14" fill="none"><path fill="#7147E8" stroke="#7147E8" stroke-width=".2" d="M11.278 2.166H9.955v-.592c0-.191-.21-.278-.4-.278H8.526C8.283.599 7.674.25 6.977.25a1.584 1.584 0 0 0-1.549 1.045h-1.01c-.19 0-.382.087-.382.278v.592H2.712a1.48 1.48 0 0 0-1.462 1.41v8.85c0 .767.696 1.324 1.462 1.324h8.566c.766 0 1.462-.557 1.462-1.323v-8.85a1.48 1.48 0 0 0-1.462-1.41Zm-6.546-.174h.957a.383.383 0 0 0 .331-.313 1.01 1.01 0 0 1 .958-.784.992.992 0 0 1 .94.784c.031.171.174.3.348.313h.992v1.393H4.732V1.992Zm7.312 10.435c0 .383-.383.627-.766.627H2.712c-.383 0-.766-.244-.766-.627v-8.85a.783.783 0 0 1 .766-.714h1.324v.887a.366.366 0 0 0 .383.331h5.135c.2.011.374-.133.4-.33v-.888h1.324c.4.007.73.315.766.713v8.85Z"/><path fill="#7147E8" stroke="#7147E8" stroke-width=".2" d="M5.663 9.525a.283.283 0 0 0-.396-.014l-.906.863-.382-.396a.283.283 0 0 0-.397-.014.297.297 0 0 0 0 .41l.58.595c.05.056.123.087.199.085a.283.283 0 0 0 .198-.085L5.663 9.92a.269.269 0 0 0 0-.396ZM10.243 10H7.368c-.138 0-.25.167-.25.374s.112.375.25.375h2.875c.138 0 .25-.168.25-.375S10.38 10 10.243 10ZM5.663 6.526a.283.283 0 0 0-.396-.014l-.906.863-.382-.396a.283.283 0 0 0-.397-.014.297.297 0 0 0 0 .41l.58.594c.05.057.123.088.199.085a.283.283 0 0 0 .198-.085l1.104-1.047a.269.269 0 0 0 0-.396ZM10.243 7H7.368c-.138 0-.25.168-.25.375s.112.375.25.375h2.875c.138 0 .25-.168.25-.375S10.38 7 10.243 7Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -11,13 +11,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { Popover } from 'antd'; import { Button, Popover, Space, Typography } from 'antd';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import classNames from 'classnames'; import classNames from 'classnames';
import { t } from 'i18next'; import { t } from 'i18next';
import { isFunction, isUndefined } from 'lodash'; import { isFunction, isUndefined } from 'lodash';
import React, { FC, Fragment } from 'react'; import React, { FC, Fragment } from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { ReactComponent as IconTaskColor } from '../../../assets/svg/Task-ic.svg';
import { EntityField } from '../../../constants/Feeds.constants'; import { EntityField } from '../../../constants/Feeds.constants';
import { EntityType } from '../../../enums/entity.enum'; import { EntityType } from '../../../enums/entity.enum';
import { ThreadType } from '../../../generated/entity/feed/thread'; import { ThreadType } from '../../../generated/entity/feed/thread';
@ -157,18 +158,18 @@ const Description: FC<DescriptionProps> = ({
const getDescriptionTaskElement = () => { const getDescriptionTaskElement = () => {
return !isUndefined(tasks) ? ( return !isUndefined(tasks) ? (
<button <Button
className="tw-w-7 tw-h-7 tw-mr-2 tw-flex-none link-text focus:tw-outline-none" className="w-7 h-7 m-r-xs p-0"
data-testid="description-task" data-testid="description-task"
type="text"
onClick={() => onThreadLinkSelect?.(tasks.entityLink, ThreadType.Task)}> onClick={() => onThreadLinkSelect?.(tasks.entityLink, ThreadType.Task)}>
<span className="tw-flex"> <Space align="center" className="w-full h-full" size={3}>
<SVGIcons alt="tasks" icon={Icons.TASK_ICON} width="16px" />{' '} <IconTaskColor height={16} name="tasks" width={16} />
<span className="tw-ml-1" data-testid="description-tasks-count"> <Typography.Text data-testid="description-tasks-count">
{' '}
{tasks.count} {tasks.count}
</span> </Typography.Text>
</span> </Space>
</button> </Button>
) : null; ) : null;
}; };

View File

@ -36,6 +36,7 @@
.manage-dropdown-button:focus { .manage-dropdown-button:focus {
.manage-dropdown-icon { .manage-dropdown-icon {
color: @white; color: @white;
font-weight: 600;
} }
background-color: @manage-button-bg-primary; background-color: @manage-button-bg-primary;
} }

View File

@ -121,6 +121,7 @@
"configure-dbt-model": "Configure dbt Model", "configure-dbt-model": "Configure dbt Model",
"configure-entity": "Configure {{entity}}", "configure-entity": "Configure {{entity}}",
"configure-glossary-term": "Configure Glossary Term", "configure-glossary-term": "Configure Glossary Term",
"configure-test-case": "Configure test case",
"confirm": "Confirm", "confirm": "Confirm",
"confirm-lowercase": "confirm", "confirm-lowercase": "confirm",
"confirm-new-password": "Confirm New Password", "confirm-new-password": "Confirm New Password",
@ -243,6 +244,7 @@
"elastic-search-re-index": "ElasticsearchReindex", "elastic-search-re-index": "ElasticsearchReindex",
"elasticsearch": "Elasticsearch", "elasticsearch": "Elasticsearch",
"email": "Email", "email": "Email",
"email-lowercase": "email",
"email-plural": "Emails", "email-plural": "Emails",
"enable-debug-log": "Enable Debug Log", "enable-debug-log": "Enable Debug Log",
"enable-partition": "Enable Partition", "enable-partition": "Enable Partition",
@ -254,7 +256,9 @@
"endpoint-url-for-aws": "EndPoint URL for the AWS", "endpoint-url-for-aws": "EndPoint URL for the AWS",
"enter": "Enter", "enter": "Enter",
"enter-entity": "Enter {{entity}}", "enter-entity": "Enter {{entity}}",
"enter-entity-name": "Enter {{entity}} name",
"enter-field-description": "Enter {{field}} description", "enter-field-description": "Enter {{field}} description",
"enter-last-name": "Enter last name",
"enter-name": "Enter Name", "enter-name": "Enter Name",
"enter-property-description": "Enter Property Description", "enter-property-description": "Enter Property Description",
"enter-property-value": "Enter Property Value", "enter-property-value": "Enter Property Value",
@ -263,6 +267,7 @@
"entity-does-not-have-followers": "{{entityName}} doesn't have any followers yet", "entity-does-not-have-followers": "{{entityName}} doesn't have any followers yet",
"entity-index": "{{entity}} index", "entity-index": "{{entity}} index",
"entity-ingestion-added-successfully": "{{entity}} Ingestion Added Successfully", "entity-ingestion-added-successfully": "{{entity}} Ingestion Added Successfully",
"entity-name": "{{entity}} Name",
"entity-plural": "Entities", "entity-plural": "Entities",
"entity-proportion": "{{entity}} Proportion", "entity-proportion": "{{entity}} Proportion",
"entity-service": "{{entity}} Service", "entity-service": "{{entity}} Service",
@ -292,6 +297,8 @@
"field-required": "{{field}} is required", "field-required": "{{field}} is required",
"field-required-plural": "{{field}} are required", "field-required-plural": "{{field}} are required",
"filter-plural": "Filters", "filter-plural": "Filters",
"first": "First",
"first-lowercase": "first",
"flush-interval-secs": "Flush Interval (secs)", "flush-interval-secs": "Flush Interval (secs)",
"follow": "Follow", "follow": "Follow",
"followed-lowercase": "followed", "followed-lowercase": "followed",
@ -371,8 +378,10 @@
"kpi-name": "KPI Name", "kpi-name": "KPI Name",
"kpi-title": "Key Performance Indicators (KPI)", "kpi-title": "Key Performance Indicators (KPI)",
"kpi-uppercase": "KPI", "kpi-uppercase": "KPI",
"last": "Last",
"last-error": "Last error", "last-error": "Last error",
"last-failed-at": "Last Failed At", "last-failed-at": "Last Failed At",
"last-lowercase": "last",
"last-no-of-day-plural": "Last {{day}} Days", "last-no-of-day-plural": "Last {{day}} Days",
"last-number-of-days": "Last {{numberOfDays}} days", "last-number-of-days": "Last {{numberOfDays}} days",
"last-run": "Last Run", "last-run": "Last Run",
@ -481,6 +490,7 @@
"partitions": "Partitions", "partitions": "Partitions",
"passed": "Passed", "passed": "Passed",
"password": "Password", "password": "Password",
"password-lowercase": "password",
"password-not-match": "Password Doesn't Match", "password-not-match": "Password Doesn't Match",
"password-type": "{{type}} Password", "password-type": "{{type}} Password",
"pause": "Pause", "pause": "Pause",
@ -497,6 +507,7 @@
"pipeline-plural": "Pipelines", "pipeline-plural": "Pipelines",
"pipeline-state": "Pipeline State", "pipeline-state": "Pipeline State",
"please-enter-value": "Please enter {{name}} value", "please-enter-value": "Please enter {{name}} value",
"please-password-type-first": "Please type password first",
"please-select": "Please Select", "please-select": "Please Select",
"plus-symbol": "+", "plus-symbol": "+",
"policy": "Policy", "policy": "Policy",
@ -613,6 +624,7 @@
"select-column-plural-to-exclude": "Select Columns to Exclude", "select-column-plural-to-exclude": "Select Columns to Exclude",
"select-column-plural-to-include": "Select Columns to Include", "select-column-plural-to-include": "Select Columns to Include",
"select-field": "Select {{field}}", "select-field": "Select {{field}}",
"select-team-plural": "Select teams",
"select-teams": "Select teams", "select-teams": "Select teams",
"select-to-search": "Search to Select", "select-to-search": "Search to Select",
"select-type": "Select type", "select-type": "Select type",
@ -711,6 +723,7 @@
"to-lowercase": "to", "to-lowercase": "to",
"token-end-point": "TokenEndpoint", "token-end-point": "TokenEndpoint",
"token-expiration": "Token Expiration", "token-expiration": "Token Expiration",
"token-expired": "Token Expired",
"token-security": "Token Security", "token-security": "Token Security",
"token-uri": "Token URI", "token-uri": "Token URI",
"topic": "Topic", "topic": "Topic",
@ -806,6 +819,7 @@
"announcement-created-successfully": "Announcement created successfully!", "announcement-created-successfully": "Announcement created successfully!",
"announcement-invalid-start-time": "Announcement start time must be earlier than the end time.", "announcement-invalid-start-time": "Announcement start time must be earlier than the end time.",
"are-you-sure": "Are you sure?", "are-you-sure": "Are you sure?",
"are-you-sure-delete-entity": "Are you sure you want to delete the property {{entity}}",
"are-you-sure-delete-property": "Are you sure you want to delete the property {{propertyName}}?", "are-you-sure-delete-property": "Are you sure you want to delete the property {{propertyName}}?",
"are-you-sure-delete-tag": "Are you sure you want to delete the {{type}} \"{{tagName}}\"?", "are-you-sure-delete-tag": "Are you sure you want to delete the {{type}} \"{{tagName}}\"?",
"are-you-sure-to-revoke-access": "Are you sure you want to revoke access for JWT token?", "are-you-sure-to-revoke-access": "Are you sure you want to revoke access for JWT token?",
@ -872,10 +886,13 @@
"enter-test-suite-name": "Enter test suite name", "enter-test-suite-name": "Enter test suite name",
"enter-your-registered-email": "Enter your registered email to receive password reset link", "enter-your-registered-email": "Enter your registered email to receive password reset link",
"entity-already-exists": "{{entity}} already exists.", "entity-already-exists": "{{entity}} already exists.",
"entity-delimiters-not-allowed": "Name with delimiters are not allowed",
"entity-is-not-valid": "{{entity}} is not valid", "entity-is-not-valid": "{{entity}} is not valid",
"entity-not-contain-whitespace": "{{entity}} should not contain white space",
"entity-owned-by-name": "This entity is owned by {{entityOwner}}", "entity-owned-by-name": "This entity is owned by {{entityOwner}}",
"entity-restored-error": "Error while restoring {{entity}}", "entity-restored-error": "Error while restoring {{entity}}",
"entity-restored-success": "{{entity}} restored successfully", "entity-restored-success": "{{entity}} restored successfully",
"entity-size-in-between": "{{entity}} size must be between {{min}} and {{max}}",
"error-while-fetching-access-token": "Error while fetching access token.", "error-while-fetching-access-token": "Error while fetching access token.",
"failed-status-for-entity-deploy": "<0>{{entity}}</0> has been {{entityStatus}}, but failed to deploy", "failed-status-for-entity-deploy": "<0>{{entity}}</0> has been {{entityStatus}}, but failed to deploy",
"fetch-dbt-files": "These are the available sources to fetch dbt catalog and manifest files.", "fetch-dbt-files": "These are the available sources to fetch dbt catalog and manifest files.",
@ -1052,6 +1069,7 @@
"unable-to-connect-to-your-dbt-cloud-instance": "URL to connect to your dbt cloud instance. E.g., \n https://cloud.getdbt.com or https://emea.dbt.com/", "unable-to-connect-to-your-dbt-cloud-instance": "URL to connect to your dbt cloud instance. E.g., \n https://cloud.getdbt.com or https://emea.dbt.com/",
"usage-ingestion-description": "Usage ingestion can be configured and deployed after a metadata ingestion has been set up. The usage ingestion workflow obtains the query log and table creation details from the underlying database and feeds it to OpenMetadata. Metadata and usage can have only one pipeline for a database service. Define the Query Log Duration (in days), Stage File Location, and Result Limit to start.", "usage-ingestion-description": "Usage ingestion can be configured and deployed after a metadata ingestion has been set up. The usage ingestion workflow obtains the query log and table creation details from the underlying database and feeds it to OpenMetadata. Metadata and usage can have only one pipeline for a database service. Define the Query Log Duration (in days), Stage File Location, and Result Limit to start.",
"use-fqn-for-filtering-message": "Regex will be applied on fully qualified name (e.g service_name.db_name.schema_name.table_name) instead of raw name (e.g. table_name).", "use-fqn-for-filtering-message": "Regex will be applied on fully qualified name (e.g service_name.db_name.schema_name.table_name) instead of raw name (e.g. table_name).",
"user-verified-successfully": "User Verified Successfully",
"valid-url-endpoint": "Endpoints should be valid URL", "valid-url-endpoint": "Endpoints should be valid URL",
"view-deleted-teams": "View All the Deleted Teams, which come under this Team.", "view-deleted-teams": "View All the Deleted Teams, which come under this Team.",
"view-sample-data": "To view Sample Data, run the Profiler Ingestion. Please refer to this doc to schedule the", "view-sample-data": "To view Sample Data, run the Profiler Ingestion. Please refer to this doc to schedule the",

View File

@ -53,11 +53,11 @@ const AddRulePage = () => {
const breadcrumb = useMemo( const breadcrumb = useMemo(
() => [ () => [
{ {
name: 'Settings', name: t('label.setting-plural'),
url: getSettingPath(), url: getSettingPath(),
}, },
{ {
name: 'Policies', name: t('label.policy-plural'),
url: policiesPath, url: policiesPath,
}, },
{ {
@ -66,7 +66,9 @@ const AddRulePage = () => {
}, },
{ {
name: 'Add New Rule', name: t('label.add-new-entity', {
entity: t('label.rule'),
}),
url: '', url: '',
}, },
], ],

View File

@ -99,10 +99,10 @@ describe('Test Roles List Component', () => {
const container = await screen.findByTestId('policies-list-table'); const container = await screen.findByTestId('policies-list-table');
const nameCol = await screen.findByText('Name'); const nameCol = await screen.findByText('label.name');
const descriptionCol = await screen.findByText('Description'); const descriptionCol = await screen.findByText('label.description');
const rolesCol = await screen.findByText('Roles'); const rolesCol = await screen.findByText('label.role-plural');
const actionsCol = await screen.findByText('Actions'); const actionsCol = await screen.findByText('label.action-plural');
expect(container).toBeInTheDocument(); expect(container).toBeInTheDocument();
expect(nameCol).toBeInTheDocument(); expect(nameCol).toBeInTheDocument();

View File

@ -19,6 +19,7 @@ import { usePermissionProvider } from 'components/PermissionProvider/PermissionP
import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider.interface'; import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider.interface';
import { isEmpty, isUndefined, uniqueId } from 'lodash'; import { isEmpty, isUndefined, uniqueId } from 'lodash';
import React, { FC, useMemo, useState } from 'react'; import React, { FC, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { import {
NO_PERMISSION_FOR_ACTION, NO_PERMISSION_FOR_ACTION,
@ -45,6 +46,7 @@ interface PolicyListProps {
} }
const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => { const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => {
const { t } = useTranslation();
const [selectedPolicy, setSelectedPolicy] = useState<Policy>(); const [selectedPolicy, setSelectedPolicy] = useState<Policy>();
const { permissions } = usePermissionProvider(); const { permissions } = usePermissionProvider();
@ -66,7 +68,7 @@ const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => {
const columns: ColumnsType<Policy> = useMemo(() => { const columns: ColumnsType<Policy> = useMemo(() => {
return [ return [
{ {
title: 'Name', title: t('label.name'),
dataIndex: 'name', dataIndex: 'name',
width: '200px', width: '200px',
key: 'name', key: 'name',
@ -80,7 +82,7 @@ const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => {
), ),
}, },
{ {
title: 'Description', title: t('label.description'),
dataIndex: 'description', dataIndex: 'description',
key: 'description', key: 'description',
render: (_, record) => ( render: (_, record) => (
@ -88,7 +90,7 @@ const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => {
), ),
}, },
{ {
title: 'Roles', title: t('label.role-plural'),
dataIndex: 'roles', dataIndex: 'roles',
width: '250px', width: '250px',
key: 'roles', key: 'roles',
@ -149,7 +151,7 @@ const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => {
}, },
}, },
{ {
title: 'Actions', title: t('label.action-plural'),
dataIndex: 'actions', dataIndex: 'actions',
width: '80px', width: '80px',
key: 'actions', key: 'actions',
@ -158,7 +160,9 @@ const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => {
<Tooltip <Tooltip
placement="left" placement="left"
title={ title={
deletePolicyPermission ? 'Delete' : NO_PERMISSION_FOR_ACTION deletePolicyPermission
? t('label.delete')
: NO_PERMISSION_FOR_ACTION
}> }>
<Button <Button
data-testid={`delete-action-${getEntityName(record)}`} data-testid={`delete-action-${getEntityName(record)}`}
@ -190,9 +194,9 @@ const PoliciesList: FC<PolicyListProps> = ({ policies, fetchPolicies }) => {
<DeleteWidgetModal <DeleteWidgetModal
afterDeleteAction={fetchPolicies} afterDeleteAction={fetchPolicies}
allowSoftDelete={false} allowSoftDelete={false}
deleteMessage={`Are you sure you want to delete ${getEntityName( deleteMessage={t('message.are-you-sure-delete-entity', {
selectedPolicy entity: getEntityName(selectedPolicy),
)}`} })}
entityId={selectedPolicy.id} entityId={selectedPolicy.id}
entityName={getEntityName(selectedPolicy)} entityName={getEntityName(selectedPolicy)}
entityType={EntityType.POLICY} entityType={EntityType.POLICY}

View File

@ -124,7 +124,11 @@ const PoliciesListPage = () => {
<Tooltip <Tooltip
placement="left" placement="left"
title={ title={
addPolicyPermission ? 'Add Policy' : NO_PERMISSION_FOR_ACTION addPolicyPermission
? t('label.add-entity', {
entity: t('label.policy'),
})
: NO_PERMISSION_FOR_ACTION
}> }>
<Button <Button
data-testid="add-policy" data-testid="add-policy"

View File

@ -18,6 +18,7 @@ import classNames from 'classnames';
import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichTextEditorPreviewer'; import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichTextEditorPreviewer';
import Loader from 'components/Loader/Loader'; import Loader from 'components/Loader/Loader';
import React, { FC, useEffect, useState } from 'react'; import React, { FC, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { getPolicies, getRoles } from 'rest/rolesAPIV1'; import { getPolicies, getRoles } from 'rest/rolesAPIV1';
import { EntityType } from '../../../enums/entity.enum'; import { EntityType } from '../../../enums/entity.enum';
import { Policy } from '../../../generated/entity/policies/policy'; import { Policy } from '../../../generated/entity/policies/policy';
@ -46,6 +47,7 @@ const AddAttributeModal: FC<Props> = ({
selectedKeys, selectedKeys,
isModalLoading, isModalLoading,
}) => { }) => {
const { t } = useTranslation();
const [data, setData] = useState<EntityReference[]>([]); const [data, setData] = useState<EntityReference[]>([]);
const [searchedData, setSearchedData] = useState<EntityReference[]>([]); const [searchedData, setSearchedData] = useState<EntityReference[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(false); const [isLoading, setIsLoading] = useState<boolean>(false);
@ -149,7 +151,9 @@ const AddAttributeModal: FC<Props> = ({
<Col span={24}> <Col span={24}>
<Input <Input
data-testid="search-input" data-testid="search-input"
placeholder={`Search ${type}`} placeholder={t('label.search-entity', {
entity: type,
})}
prefix={<SearchOutlined style={{ color: '#37352F4D' }} />} prefix={<SearchOutlined style={{ color: '#37352F4D' }} />}
onChange={(e) => handleSearch(e.target.value)} onChange={(e) => handleSearch(e.target.value)}
/> />

View File

@ -68,10 +68,10 @@ describe('Test Roles List Component', () => {
const container = await screen.findByTestId('roles-list-table'); const container = await screen.findByTestId('roles-list-table');
const nameCol = await screen.findByText('Name'); const nameCol = await screen.findByText('label.name');
const descriptionCol = await screen.findByText('Description'); const descriptionCol = await screen.findByText('label.description');
const policiesCol = await screen.findByText('Policies'); const policiesCol = await screen.findByText('label.policy-plural');
const actionsCol = await screen.findByText('Actions'); const actionsCol = await screen.findByText('label.action-plural');
expect(container).toBeInTheDocument(); expect(container).toBeInTheDocument();
expect(nameCol).toBeInTheDocument(); expect(nameCol).toBeInTheDocument();

View File

@ -19,6 +19,7 @@ import { usePermissionProvider } from 'components/PermissionProvider/PermissionP
import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider.interface'; import { ResourceEntity } from 'components/PermissionProvider/PermissionProvider.interface';
import { isEmpty, isUndefined, uniqueId } from 'lodash'; import { isEmpty, isUndefined, uniqueId } from 'lodash';
import React, { FC, useMemo, useState } from 'react'; import React, { FC, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { import {
NO_PERMISSION_FOR_ACTION, NO_PERMISSION_FOR_ACTION,
@ -46,6 +47,7 @@ interface RolesListProps {
} }
const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => { const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => {
const { t } = useTranslation();
const [selectedRole, setSelectedRole] = useState<Role>(); const [selectedRole, setSelectedRole] = useState<Role>();
const { permissions } = usePermissionProvider(); const { permissions } = usePermissionProvider();
@ -67,7 +69,7 @@ const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => {
const columns: ColumnsType<Role> = useMemo(() => { const columns: ColumnsType<Role> = useMemo(() => {
return [ return [
{ {
title: 'Name', title: t('label.name'),
dataIndex: 'name', dataIndex: 'name',
width: '200px', width: '200px',
key: 'name', key: 'name',
@ -81,7 +83,7 @@ const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => {
), ),
}, },
{ {
title: 'Description', title: t('label.description'),
dataIndex: 'description', dataIndex: 'description',
key: 'description', key: 'description',
render: (_, record) => ( render: (_, record) => (
@ -89,7 +91,7 @@ const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => {
), ),
}, },
{ {
title: 'Policies', title: t('label.policy-plural'),
dataIndex: 'policies', dataIndex: 'policies',
width: '250px', width: '250px',
key: 'policies', key: 'policies',
@ -150,7 +152,7 @@ const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => {
}, },
}, },
{ {
title: 'Actions', title: t('label.action-plural'),
dataIndex: 'actions', dataIndex: 'actions',
width: '80px', width: '80px',
key: 'actions', key: 'actions',
@ -159,7 +161,9 @@ const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => {
<Tooltip <Tooltip
placement="left" placement="left"
title={ title={
deleteRolePermission ? 'Delete' : NO_PERMISSION_FOR_ACTION deleteRolePermission
? t('label.delete')
: NO_PERMISSION_FOR_ACTION
}> }>
<Button <Button
data-testid={`delete-action-${getEntityName(record)}`} data-testid={`delete-action-${getEntityName(record)}`}
@ -193,9 +197,9 @@ const RolesList: FC<RolesListProps> = ({ roles, fetchRoles }) => {
<DeleteWidgetModal <DeleteWidgetModal
afterDeleteAction={fetchRoles} afterDeleteAction={fetchRoles}
allowSoftDelete={false} allowSoftDelete={false}
deleteMessage={`Are you sure you want to delete ${getEntityName( deleteMessage={t('message.are-you-sure-delete-entity', {
selectedRole entity: getEntityName(selectedRole),
)}`} })}
entityId={selectedRole.id} entityId={selectedRole.id}
entityName={getEntityName(selectedRole)} entityName={getEntityName(selectedRole)}
entityType={EntityType.ROLE} entityType={EntityType.ROLE}

View File

@ -125,7 +125,13 @@ const RolesListPage = () => {
<PageHeader data={PAGE_HEADERS.ROLES} /> <PageHeader data={PAGE_HEADERS.ROLES} />
<Tooltip <Tooltip
placement="left" placement="left"
title={addRolePermission ? 'Add Role' : NO_PERMISSION_FOR_ACTION}> title={
addRolePermission
? t('label.add-entity', {
entity: t('label.role'),
})
: NO_PERMISSION_FOR_ACTION
}>
<Button <Button
data-testid="add-role" data-testid="add-role"
disabled={!addRolePermission} disabled={!addRolePermission}

View File

@ -60,7 +60,7 @@ const AccountActivationConfirmation = () => {
<Space align="center" direction="vertical"> <Space align="center" direction="vertical">
<Alert <Alert
showIcon showIcon
message="User Verified Successfully" message={t('label.user-verified-successfully')}
type="success" type="success"
/> />
<div className="mt-12" onClick={handleBackToLogin}> <div className="mt-12" onClick={handleBackToLogin}>
@ -73,7 +73,7 @@ const AccountActivationConfirmation = () => {
) : ( ) : (
<div className="mt-12 w-16"> <div className="mt-12 w-16">
<Space align="center" direction="vertical"> <Space align="center" direction="vertical">
<Alert showIcon message="Token Expired" type="error" /> <Alert showIcon message={t('label.token-expired')} type="error" />
<div className="mt-12"> <div className="mt-12">
<Typography.Link underline> <Typography.Link underline>
{t('label.regenerate-registration-token')} {t('label.regenerate-registration-token')}

View File

@ -67,11 +67,17 @@ const BasicSignUp = () => {
const handleLogin = () => history.push(ROUTES.SIGNIN); const handleLogin = () => history.push(ROUTES.SIGNIN);
const validationMessages = { const validationMessages = {
required: '${label} is required', required: t('message.field-text-is-required', {
fieldText: '${label}',
}),
types: { types: {
email: '${label} is not valid', email: t('message.entity-is-not-valid', {
entity: '${label}',
}),
}, },
whitespace: '${label} should not contain white space', whitespace: t('message.entity-not-contain-whitespace', {
entity: '${label}',
}),
}; };
return ( return (
@ -97,25 +103,37 @@ const BasicSignUp = () => {
validateMessages={validationMessages} validateMessages={validationMessages}
onFinish={handleSubmit}> onFinish={handleSubmit}>
<Form.Item <Form.Item
label="First Name" label={t('label.entity-name', {
entity: t('label.first'),
})}
name="firstName" name="firstName"
rules={[{ whitespace: true, required: true }]}> rules={[{ whitespace: true, required: true }]}>
<Input placeholder="Enter first name" /> <Input
placeholder={t('label.enter-entity-name', {
entity: t('label.first-lowercase'),
})}
/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Last Name" label={t('label.entity-name', {
entity: t('label.last'),
})}
name="lastName" name="lastName"
rules={[{ whitespace: true, required: true }]}> rules={[{ whitespace: true, required: true }]}>
<Input placeholder="Enter last name" /> <Input placeholder={t('label.enter-last-name')} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Email" label={t('label.email')}
name="email" name="email"
rules={[{ type: 'email', required: true }]}> rules={[{ type: 'email', required: true }]}>
<Input placeholder="Enter email" /> <Input
placeholder={t('label.enter-entity', {
entity: t('label.email-lowercase'),
})}
/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Password" label={t('label.password')}
name="password" name="password"
rules={[ rules={[
{ {
@ -126,22 +144,28 @@ const BasicSignUp = () => {
message: passwordErrorMessage, message: passwordErrorMessage,
}, },
]}> ]}>
<Input.Password placeholder="Enter password" /> <Input.Password
placeholder={t('label.enter-entity', {
entity: t('label.password-lowercase'),
})}
/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Confirm Password" label={t('label.password-type', {
type: t('label.confirm'),
})}
name="confirmPassword" name="confirmPassword"
rules={[ rules={[
{ {
validator: (_, value) => { validator: (_, value) => {
if (isEmpty(password)) { if (isEmpty(password)) {
return Promise.reject( return Promise.reject(
'Please type password first' t('label.please-password-type-first')
); );
} }
if (value !== password) { if (value !== password) {
return Promise.reject( return Promise.reject(
"Password doesn't match" t('label.password-not-match')
); );
} }
@ -149,7 +173,9 @@ const BasicSignUp = () => {
}, },
}, },
]}> ]}>
<Input.Password placeholder="Confirm your password" /> <Input.Password
placeholder={t('label.confirm-password')}
/>
</Form.Item> </Form.Item>
<Button <Button

View File

@ -468,11 +468,19 @@ const TagsPage = () => {
if (errorDataTag || forceSet) { if (errorDataTag || forceSet) {
const errData: { [key: string]: string } = {}; const errData: { [key: string]: string } = {};
if (!data.name.trim()) { if (!data.name.trim()) {
errData['name'] = 'Name is required'; errData['name'] = t('label.field-required', {
field: t('label.name'),
});
} else if (delimiterRegex.test(data.name)) { } else if (delimiterRegex.test(data.name)) {
errData['name'] = 'Name with delimiters are not allowed'; errData['name'] = t('message.entity-delimiters-not-allowed', {
entity: t('label.name'),
});
} else if (data.name.length < 2 || data.name.length > 64) { } else if (data.name.length < 2 || data.name.length > 64) {
errData['name'] = 'Name size must be between 2 and 64'; errData['name'] = t('message.entity-size-in-between', {
entity: t('label.name'),
max: 64,
min: 2,
});
} }
setErrorDataTag(errData); setErrorDataTag(errData);

View File

@ -20,6 +20,9 @@
.w-6 { .w-6 {
width: 1.5rem; width: 1.5rem;
} }
.w-7 {
width: 28px;
}
.w-8 { .w-8 {
width: 32px; width: 32px;
} }