mirror of
https://github.com/open-metadata/OpenMetadata
synced 2026-05-24 09:39:11 +00:00
Rules library (#24748)
* Add DQ Rules Library
* Add DQ Rules Library - Add Tests and enable testDefinitions through APIs to list
* Add DQ Rules Library - Add Tests and enable testDefinitions through APIs to list
* Add DQ Rules Library - Add Tests and enable testDefinitions through APIs to list
* Update generated TypeScript types
* Add DQ Rules Library - Add Tests and enable testDefinitions through APIs to list
* Add DQ Rules Library - Add Tests and enable testDefinitions through APIs to list
* Update generated TypeScript types
* Refactor tests to use toStrictEqual for string comparisons and improve consistency
- Updated various test files to replace `toBe` with `toStrictEqual` for string assertions in ImportStatus, SummaryCard, TabsLabel, and others.
- Enhanced regex tests to ensure accurate validation of entity names and tags.
- Added new translations for test platform warnings in en-us.json.
- Improved utility tests for alerts, authentication, CSV handling, and task messages to use `toEqual` for better clarity.
* Refactor TestDefinitionForm and TestDefinitionList components to use updated API methods and improve SQL expression handling
* Enhance TestDefinitionList component with permission checks for edit and delete actions, and update tests to reflect changes in permission handling
* Remove debug log from handleSubmit in TestDefinitionForm component
* Add permission loading state and enhance permission handling in TestDefinitionList component
* Update generated TypeScript types
* Update generated TypeScript types
* Update generated TypeScript types
* fix build failure
* Revert "Update generated TypeScript types"
This reverts commit 67b062216f.
* Enhance TestDefinitionForm and TestDefinitionList components with improved UI and pagination handling
* fix: update RulesLibrary tests and enhance TestDefinitionForm styling
* fix: Enhance TestDefinitionForm with error handling and improved UX
* fix: Update test definition handling and improve rendering in TestDefinitionList
* fix: Refactor TestDefinitionPermissions tests for improved permission checks and API context handling
* fix: Update system test definition retrieval to use findLast for improved accuracy
* feat: Add end-to-end tests for Rules Library and Test Definition Permissions
* fix: Update edit button visibility check to use beDisabled for better clarity
* fix: Refactor response handling in TestDefinitionPermissions tests for improved reliability
* move migrations execution order
* fix: remove existing columns
* style: remove migration extra line break
* chore: fix migration
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Shailesh Parmar <shailesh.parmar.webdev@gmail.com>
Co-authored-by: TeddyCr <teddy.crepineau@gmail.com>
This commit is contained in:
parent
f5cf3190c4
commit
69ef1371bc
74 changed files with 4077 additions and 343 deletions
|
|
@ -30,3 +30,23 @@ CREATE TABLE IF NOT EXISTS audit_log_event (
|
|||
KEY idx_audit_log_service_name_ts (service_name, event_ts DESC),
|
||||
KEY idx_audit_log_created_at (created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
|
||||
|
||||
-- Add enabled field to test_definition table for Rules Library feature
|
||||
-- This allows administrators to enable/disable test definitions in the rules library
|
||||
|
||||
-- Add virtual column for enabled field
|
||||
-- CAST is needed to convert JSON boolean (true/false) to TINYINT (1/0)
|
||||
ALTER TABLE test_definition
|
||||
ADD COLUMN enabled TINYINT(1)
|
||||
GENERATED ALWAYS AS (COALESCE(CAST(json_extract(json, '$.enabled') AS UNSIGNED), 1))
|
||||
VIRTUAL;
|
||||
|
||||
-- Add index for filtering enabled/disabled test definitions
|
||||
CREATE INDEX idx_test_definition_enabled ON test_definition(enabled);
|
||||
|
||||
-- Set all existing test definitions to enabled by default
|
||||
UPDATE test_definition
|
||||
SET json = JSON_SET(json, '$.enabled', true)
|
||||
WHERE json_extract(json, '$.enabled') IS NULL;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,29 @@ CREATE TABLE IF NOT EXISTS audit_log_event (
|
|||
created_at BIGINT DEFAULT (EXTRACT(EPOCH FROM NOW()) * 1000)::BIGINT
|
||||
);
|
||||
|
||||
-- Add indexes for efficient filtering
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_actor_type_ts ON audit_log_event (actor_type, event_ts DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_service_name_ts ON audit_log_event (service_name, event_ts DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_created_at ON audit_log_event (created_at);
|
||||
|
||||
|
||||
-- Add enabled field to test_definition table for Rules Library feature
|
||||
-- This allows administrators to enable/disable test definitions in the rules library
|
||||
|
||||
-- Add generated column for enabled field with default true for existing rows
|
||||
ALTER TABLE test_definition
|
||||
ADD COLUMN IF NOT EXISTS enabled BOOLEAN GENERATED ALWAYS AS (
|
||||
COALESCE((json ->> 'enabled')::boolean, true)
|
||||
) STORED;
|
||||
|
||||
-- Add index for filtering enabled/disabled test definitions
|
||||
CREATE INDEX IF NOT EXISTS idx_test_definition_enabled ON test_definition(enabled);
|
||||
|
||||
-- Set all existing test definitions to enabled by default
|
||||
UPDATE test_definition
|
||||
SET json = jsonb_set(json::jsonb, '{enabled}', 'true'::jsonb, true)::json
|
||||
WHERE json ->> 'enabled' IS NULL;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_audit_log_event_change_event_id
|
||||
ON audit_log_event (change_event_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -6286,12 +6286,14 @@ public interface CollectionDAO {
|
|||
String testPlatform = filter.getQueryParam("testPlatform");
|
||||
String supportedDataType = filter.getQueryParam("supportedDataType");
|
||||
String supportedService = filter.getQueryParam("supportedService");
|
||||
String enabled = filter.getQueryParam("enabled");
|
||||
String condition = filter.getCondition();
|
||||
|
||||
if (entityType == null
|
||||
&& testPlatform == null
|
||||
&& supportedDataType == null
|
||||
&& supportedService == null) {
|
||||
&& supportedService == null
|
||||
&& enabled == null) {
|
||||
return EntityDAO.super.listBefore(filter, limit, beforeName, beforeId);
|
||||
}
|
||||
|
||||
|
|
@ -6331,6 +6333,12 @@ public interface CollectionDAO {
|
|||
+ "OR json->>'supportedServices' LIKE :supportedServiceLike) ");
|
||||
}
|
||||
|
||||
if (enabled != null) {
|
||||
String enabledValue = Boolean.parseBoolean(enabled) ? "TRUE" : "FALSE";
|
||||
mysqlCondition.append("AND enabled=" + enabledValue + " ");
|
||||
psqlCondition.append("AND enabled=" + enabledValue + " ");
|
||||
}
|
||||
|
||||
return listBefore(
|
||||
getTableName(),
|
||||
filter.getQueryParams(),
|
||||
|
|
@ -6347,12 +6355,14 @@ public interface CollectionDAO {
|
|||
String testPlatform = filter.getQueryParam("testPlatform");
|
||||
String supportedDataType = filter.getQueryParam("supportedDataType");
|
||||
String supportedService = filter.getQueryParam("supportedService");
|
||||
String enabled = filter.getQueryParam("enabled");
|
||||
String condition = filter.getCondition();
|
||||
|
||||
if (entityType == null
|
||||
&& testPlatform == null
|
||||
&& supportedDataType == null
|
||||
&& supportedService == null) {
|
||||
&& supportedService == null
|
||||
&& enabled == null) {
|
||||
return EntityDAO.super.listAfter(filter, limit, afterName, afterId);
|
||||
}
|
||||
|
||||
|
|
@ -6392,6 +6402,12 @@ public interface CollectionDAO {
|
|||
+ "OR json->>'supportedServices' LIKE :supportedServiceLike) ");
|
||||
}
|
||||
|
||||
if (enabled != null) {
|
||||
String enabledValue = Boolean.parseBoolean(enabled) ? "TRUE" : "FALSE";
|
||||
mysqlCondition.append("AND enabled=" + enabledValue + " ");
|
||||
psqlCondition.append("AND enabled=" + enabledValue + " ");
|
||||
}
|
||||
|
||||
return listAfter(
|
||||
getTableName(),
|
||||
filter.getQueryParams(),
|
||||
|
|
@ -6408,12 +6424,14 @@ public interface CollectionDAO {
|
|||
String testPlatform = filter.getQueryParam("testPlatform");
|
||||
String supportedDataType = filter.getQueryParam("supportedDataType");
|
||||
String supportedService = filter.getQueryParam("supportedService");
|
||||
String enabled = filter.getQueryParam("enabled");
|
||||
String condition = filter.getCondition();
|
||||
|
||||
if (entityType == null
|
||||
&& testPlatform == null
|
||||
&& supportedDataType == null
|
||||
&& supportedService == null) {
|
||||
&& supportedService == null
|
||||
&& enabled == null) {
|
||||
return EntityDAO.super.listCount(filter);
|
||||
}
|
||||
|
||||
|
|
@ -6452,6 +6470,13 @@ public interface CollectionDAO {
|
|||
+ "OR json->>'supportedServices' IS NULL "
|
||||
+ "OR json->>'supportedServices' LIKE :supportedServiceLike) ");
|
||||
}
|
||||
|
||||
if (enabled != null) {
|
||||
String enabledValue = Boolean.parseBoolean(enabled) ? "TRUE" : "FALSE";
|
||||
mysqlCondition.append("AND enabled=").append(enabledValue).append(" ");
|
||||
psqlCondition.append("AND enabled=").append(enabledValue).append(" ");
|
||||
}
|
||||
|
||||
return listCount(
|
||||
getTableName(),
|
||||
filter.getQueryParams(),
|
||||
|
|
|
|||
|
|
@ -482,6 +482,14 @@ public class TestCaseRepository extends EntityRepository<TestCase> {
|
|||
Entity.getEntity(test.getTestDefinition(), "", Include.NON_DELETED);
|
||||
test.setTestDefinition(testDefinition.getEntityReference());
|
||||
|
||||
// Validate that the test definition is enabled (only for new test cases, not updates)
|
||||
if (!update && Boolean.FALSE.equals(testDefinition.getEnabled())) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Test definition '%s' is disabled and cannot be used to create test cases",
|
||||
testDefinition.getName()));
|
||||
}
|
||||
|
||||
validateTestParameters(
|
||||
test.getParameterValues(),
|
||||
testDefinition.getParameterDefinition(),
|
||||
|
|
|
|||
|
|
@ -2,14 +2,19 @@ package org.openmetadata.service.jdbi3;
|
|||
|
||||
import static org.openmetadata.service.Entity.TEST_DEFINITION;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jdbi.v3.sqlobject.transaction.Transaction;
|
||||
import org.openmetadata.common.utils.CommonUtil;
|
||||
import org.openmetadata.schema.tests.TestDefinition;
|
||||
import org.openmetadata.schema.type.Include;
|
||||
import org.openmetadata.schema.type.ProviderType;
|
||||
import org.openmetadata.schema.type.change.ChangeSource;
|
||||
import org.openmetadata.service.Entity;
|
||||
import org.openmetadata.service.resources.dqtests.TestDefinitionResource;
|
||||
import org.openmetadata.service.util.EntityUtil;
|
||||
|
||||
@Slf4j
|
||||
public class TestDefinitionRepository extends EntityRepository<TestDefinition> {
|
||||
public TestDefinitionRepository() {
|
||||
super(
|
||||
|
|
@ -37,6 +42,55 @@ public class TestDefinitionRepository extends EntityRepository<TestDefinition> {
|
|||
if (CommonUtil.nullOrEmpty(entity.getTestPlatforms())) {
|
||||
throw new IllegalArgumentException("testPlatforms must not be empty");
|
||||
}
|
||||
// Set enabled to true by default if not specified
|
||||
if (entity.getEnabled() == null) {
|
||||
entity.setEnabled(true);
|
||||
}
|
||||
|
||||
// For updates to system test definitions, only allow changes to the enabled field
|
||||
if (update && entity.getProvider() == ProviderType.SYSTEM) {
|
||||
TestDefinition existing = find(entity.getId(), Include.ALL);
|
||||
if (existing != null) {
|
||||
validateSystemTestDefinitionUpdate(existing, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateSystemTestDefinitionUpdate(TestDefinition existing, TestDefinition updated) {
|
||||
// Check if any field other than 'enabled' is being changed
|
||||
if (!existing.getEntityType().equals(updated.getEntityType())) {
|
||||
throw new BadRequestException(
|
||||
"System test definitions cannot have their entity type modified");
|
||||
}
|
||||
if (!existing.getTestPlatforms().equals(updated.getTestPlatforms())) {
|
||||
throw new BadRequestException(
|
||||
"System test definitions cannot have their test platforms modified");
|
||||
}
|
||||
if (!CommonUtil.nullOrEmpty(existing.getSupportedDataTypes())
|
||||
&& !existing.getSupportedDataTypes().equals(updated.getSupportedDataTypes())) {
|
||||
throw new BadRequestException(
|
||||
"System test definitions cannot have their supported data types modified");
|
||||
}
|
||||
if (!CommonUtil.nullOrEmpty(existing.getParameterDefinition())
|
||||
&& !existing.getParameterDefinition().equals(updated.getParameterDefinition())) {
|
||||
throw new BadRequestException(
|
||||
"System test definitions cannot have their parameter definitions modified");
|
||||
}
|
||||
if (existing.getDataQualityDimension() != null
|
||||
&& !existing.getDataQualityDimension().equals(updated.getDataQualityDimension())) {
|
||||
throw new BadRequestException(
|
||||
"System test definitions cannot have their data quality dimension modified");
|
||||
}
|
||||
if (!CommonUtil.nullOrEmpty(existing.getSupportedServices())
|
||||
&& !existing.getSupportedServices().equals(updated.getSupportedServices())) {
|
||||
throw new BadRequestException(
|
||||
"System test definitions cannot have their supported services modified");
|
||||
}
|
||||
if (existing.getSqlExpression() != null
|
||||
&& !existing.getSqlExpression().equals(updated.getSqlExpression())) {
|
||||
throw new BadRequestException(
|
||||
"System test definitions cannot have their SQL expression modified");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -49,6 +103,15 @@ public class TestDefinitionRepository extends EntityRepository<TestDefinition> {
|
|||
// No relationships to store beyond what is stored in the super class
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preDelete(TestDefinition entity, String deletedBy) {
|
||||
// Prevent deletion of system test definitions
|
||||
if (entity.getProvider() == ProviderType.SYSTEM) {
|
||||
throw new BadRequestException(
|
||||
"System test definitions cannot be deleted. They can only be disabled by setting enabled=false.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRepository<TestDefinition>.EntityUpdater getUpdater(
|
||||
TestDefinition original,
|
||||
|
|
@ -67,13 +130,30 @@ public class TestDefinitionRepository extends EntityRepository<TestDefinition> {
|
|||
@Transaction
|
||||
@Override
|
||||
public void entitySpecificUpdate(boolean consolidatingChanges) {
|
||||
recordChange("testPlatforms", original.getTestPlatforms(), updated.getTestPlatforms());
|
||||
recordChange(
|
||||
"supportedDataTypes", original.getSupportedDataTypes(), updated.getSupportedDataTypes());
|
||||
recordChange(
|
||||
"parameterDefinition",
|
||||
original.getParameterDefinition(),
|
||||
updated.getParameterDefinition());
|
||||
// For system test definitions, only allow enabled field changes
|
||||
if (original.getProvider() == ProviderType.SYSTEM) {
|
||||
// Only record enabled field changes for system test definitions
|
||||
recordChange("enabled", original.getEnabled(), updated.getEnabled());
|
||||
} else {
|
||||
// For user/automation test definitions, allow all changes
|
||||
recordChange("testPlatforms", original.getTestPlatforms(), updated.getTestPlatforms());
|
||||
recordChange(
|
||||
"supportedDataTypes",
|
||||
original.getSupportedDataTypes(),
|
||||
updated.getSupportedDataTypes());
|
||||
recordChange(
|
||||
"parameterDefinition",
|
||||
original.getParameterDefinition(),
|
||||
updated.getParameterDefinition());
|
||||
recordChange("enabled", original.getEnabled(), updated.getEnabled());
|
||||
recordChange(
|
||||
"dataQualityDimension",
|
||||
original.getDataQualityDimension(),
|
||||
updated.getDataQualityDimension());
|
||||
recordChange(
|
||||
"supportedServices", original.getSupportedServices(), updated.getSupportedServices());
|
||||
recordChange("sqlExpression", original.getSqlExpression(), updated.getSqlExpression());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,13 @@ public class TestDefinitionResource
|
|||
"Filter test definitions by supported service. Returns test definitions that either "
|
||||
+ "have an empty supportedServices list (supporting all services) or include the specified service.")
|
||||
@QueryParam("supportedService")
|
||||
String supportedServiceParam) {
|
||||
String supportedServiceParam,
|
||||
@Parameter(
|
||||
description =
|
||||
"Filter by enabled status (true/false). If not specified, returns all test definitions.",
|
||||
schema = @Schema(type = "boolean"))
|
||||
@QueryParam("enabled")
|
||||
Boolean enabledParam) {
|
||||
ListFilter filter = new ListFilter(include);
|
||||
if (entityType != null) {
|
||||
filter.addQueryParam("entityType", entityType);
|
||||
|
|
@ -169,6 +175,9 @@ public class TestDefinitionResource
|
|||
if (supportedServiceParam != null) {
|
||||
filter.addQueryParam("supportedService", supportedServiceParam);
|
||||
}
|
||||
if (enabledParam != null) {
|
||||
filter.addQueryParam("enabled", String.valueOf(enabledParam));
|
||||
}
|
||||
return super.listInternal(
|
||||
uriInfo, securityContext, fieldsParam, filter, limitParam, before, after);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
],
|
||||
"supportsDynamicAssertion": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Accuracy"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
],
|
||||
"supportsDynamicAssertion": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Accuracy"
|
||||
}
|
||||
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
],
|
||||
"supportsDynamicAssertion": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Accuracy"
|
||||
}
|
||||
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
],
|
||||
"supportsDynamicAssertion": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Accuracy"
|
||||
}
|
||||
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
],
|
||||
"supportsDynamicAssertion": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Accuracy"
|
||||
}
|
||||
|
||||
|
|
@ -39,6 +39,7 @@
|
|||
],
|
||||
"supportsRowLevelPassedFailed": false,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Accuracy"
|
||||
}
|
||||
|
||||
|
|
@ -31,5 +31,6 @@
|
|||
"supportsRowLevelPassedFailed": true,
|
||||
"supportsDynamicAssertion": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Accuracy"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,5 +22,6 @@
|
|||
}
|
||||
],
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Completeness"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
],
|
||||
"supportsDynamicAssertion": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Accuracy"
|
||||
}
|
||||
|
||||
|
|
@ -31,5 +31,6 @@
|
|||
"supportsRowLevelPassedFailed": true,
|
||||
"supportsDynamicAssertion": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Accuracy"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,5 +24,6 @@
|
|||
],
|
||||
"supportsRowLevelPassedFailed": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Validity"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,5 +17,6 @@
|
|||
],
|
||||
"supportsRowLevelPassedFailed": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Validity"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,5 +8,6 @@
|
|||
"supportedDataTypes": ["NUMBER","TINYINT","SMALLINT","INT","BIGINT","BYTEINT","BYTES","FLOAT","DOUBLE","DECIMAL","NUMERIC","TIMESTAMP","TIMESTAMPZ","TIME","DATE","DATETIME","INTERVAL","STRING","MEDIUMTEXT","TEXT","CHAR","VARCHAR","BOOLEAN","BINARY","VARBINARY","ARRAY","BLOB","LONGBLOB","MEDIUMBLOB","MAP","STRUCT","UNION","SET","GEOGRAPHY","ENUM","JSON","UUID","VARIANT","GEOMETRY","POINT","POLYGON","LOWCARDINALITY"],
|
||||
"supportsRowLevelPassedFailed": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Completeness"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,5 +51,6 @@
|
|||
],
|
||||
"supportsRowLevelPassedFailed": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Uniqueness"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,5 +17,6 @@
|
|||
],
|
||||
"supportsRowLevelPassedFailed": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Validity"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,5 +17,6 @@
|
|||
],
|
||||
"supportsRowLevelPassedFailed": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Validity"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,5 +28,6 @@
|
|||
}
|
||||
],
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Integrity"
|
||||
}
|
||||
|
|
@ -15,5 +15,6 @@
|
|||
}
|
||||
],
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Integrity"
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
}
|
||||
],
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Integrity"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
}
|
||||
],
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Integrity"
|
||||
}
|
||||
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
],
|
||||
"supportsRowLevelPassedFailed": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "SQL"
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +59,7 @@
|
|||
}
|
||||
],
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Consistency",
|
||||
"supportedServices": [
|
||||
"Snowflake",
|
||||
|
|
|
|||
|
|
@ -29,5 +29,6 @@
|
|||
],
|
||||
"supportsDynamicAssertion": true,
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Integrity"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,5 +15,6 @@
|
|||
}
|
||||
],
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Integrity"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
}
|
||||
],
|
||||
"provider": "system",
|
||||
"enabled": true,
|
||||
"dataQualityDimension": "Integrity"
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +59,7 @@ import static org.openmetadata.service.util.TestUtils.dateToTimestamp;
|
|||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.flipkart.zjsonpatch.JsonDiff;
|
||||
import es.org.elasticsearch.client.Request;
|
||||
import es.org.elasticsearch.client.Response;
|
||||
import es.org.elasticsearch.client.RestClient;
|
||||
|
|
@ -87,7 +88,6 @@ import org.junit.jupiter.api.Assertions;
|
|||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInfo;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
|
|
@ -100,7 +100,6 @@ import org.openmetadata.schema.api.policies.CreatePolicy;
|
|||
import org.openmetadata.schema.api.teams.CreateRole;
|
||||
import org.openmetadata.schema.api.teams.CreateTeam;
|
||||
import org.openmetadata.schema.api.teams.CreateUser;
|
||||
import org.openmetadata.schema.api.tests.CreateLogicalTestCases;
|
||||
import org.openmetadata.schema.api.tests.CreateTestCase;
|
||||
import org.openmetadata.schema.api.tests.CreateTestCaseResolutionStatus;
|
||||
import org.openmetadata.schema.api.tests.CreateTestCaseResult;
|
||||
|
|
@ -144,8 +143,6 @@ import org.openmetadata.schema.type.TableData;
|
|||
import org.openmetadata.schema.type.TagLabel;
|
||||
import org.openmetadata.schema.type.TaskStatus;
|
||||
import org.openmetadata.schema.type.TestDefinitionEntityType;
|
||||
import org.openmetadata.schema.type.csv.CsvImportResult;
|
||||
import org.openmetadata.schema.utils.EntityInterfaceUtil;
|
||||
import org.openmetadata.schema.utils.JsonUtils;
|
||||
import org.openmetadata.schema.utils.ResultList;
|
||||
import org.openmetadata.search.IndexMapping;
|
||||
|
|
@ -163,7 +160,6 @@ import org.openmetadata.service.search.SearchIndexUtils;
|
|||
import org.openmetadata.service.search.SearchRepository;
|
||||
import org.openmetadata.service.search.indexes.TestCaseIndex;
|
||||
import org.openmetadata.service.security.SecurityUtil;
|
||||
import org.openmetadata.service.util.FullyQualifiedName;
|
||||
import org.openmetadata.service.util.TestUtils;
|
||||
import org.openmetadata.service.util.incidentSeverityClassifier.IncidentSeverityClassifierInterface;
|
||||
import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
|
||||
|
|
@ -5560,355 +5556,143 @@ public class TestCaseResourceTest extends EntityResourceTest<TestCase, CreateTes
|
|||
}
|
||||
|
||||
@Test
|
||||
@Tag("ImportExport")
|
||||
void testImportExport_TableLevel(TestInfo test) throws IOException {
|
||||
// Create a table with columns
|
||||
TableResourceTest tableResourceTest = new TableResourceTest();
|
||||
Column c1 = new Column().withName("c1").withDataType(BIGINT);
|
||||
Column c2 = new Column().withName("c2").withDataType(BIGINT);
|
||||
CreateTable createTable =
|
||||
tableResourceTest
|
||||
.createRequest(test)
|
||||
.withColumns(listOf(c1, c2))
|
||||
.withTableConstraints(null);
|
||||
Table table = tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
|
||||
String tableFqn = table.getFullyQualifiedName();
|
||||
void test_createTestCaseWithDisabledDefinition_400(TestInfo test) throws Exception {
|
||||
// Get the test definition
|
||||
TestDefinition testDefinition = TEST_DEFINITION1;
|
||||
|
||||
// Get test definitions by name
|
||||
TestDefinition tableRowCountDef =
|
||||
Entity.getEntityByName(
|
||||
TEST_DEFINITION, "tableRowCountToBeBetween", "", Include.NON_DELETED);
|
||||
TestDefinition columnUniquenessDef =
|
||||
Entity.getEntityByName(TEST_DEFINITION, "columnValuesToBeUnique", "", Include.NON_DELETED);
|
||||
// Disable the test definition using JSON Patch
|
||||
String originalJson = JsonUtils.pojoToJson(testDefinition);
|
||||
testDefinition.setEnabled(false);
|
||||
String updatedJson = JsonUtils.pojoToJson(testDefinition);
|
||||
|
||||
// Create test cases for the table
|
||||
CreateTestCase createTableTest =
|
||||
createRequest(getEntityName(test, 1))
|
||||
.withEntityLink(String.format("<#E::table::%s>", tableFqn))
|
||||
.withTestDefinition(tableRowCountDef.getFullyQualifiedName())
|
||||
.withDisplayName("Table Row Count Test")
|
||||
.withParameterValues(
|
||||
listOf(
|
||||
new TestCaseParameterValue().withName("minValue").withValue("10"),
|
||||
new TestCaseParameterValue().withName("maxValue").withValue("100")));
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
CreateTestCase createColumnTest =
|
||||
createRequest(getEntityName(test, 2))
|
||||
.withEntityLink(String.format("<#E::table::%s::columns::c1>", tableFqn))
|
||||
.withTestDefinition(columnUniquenessDef.getFullyQualifiedName())
|
||||
.withDisplayName("Column Uniqueness Test")
|
||||
.withDescription("Column uniqueness test description");
|
||||
WebTarget target =
|
||||
getResource("dataQuality/testDefinitions").path(testDefinition.getId().toString());
|
||||
TestUtils.patch(target, patch, TestDefinition.class, ADMIN_AUTH_HEADERS);
|
||||
|
||||
TestCase tableTest = createEntity(createTableTest, ADMIN_AUTH_HEADERS);
|
||||
TestCase columnTest = createEntity(createColumnTest, ADMIN_AUTH_HEADERS);
|
||||
// Try to create a test case with the disabled definition
|
||||
CreateTestCase create = createRequest(getEntityName(test));
|
||||
create.setEntityLink(TABLE_LINK);
|
||||
create.setTestDefinition(testDefinition.getFullyQualifiedName());
|
||||
|
||||
// Export test cases for the table
|
||||
String exportedCsv = exportCsv(tableFqn);
|
||||
assertNotNull(exportedCsv);
|
||||
assertTrue(exportedCsv.contains(tableTest.getName()));
|
||||
assertTrue(exportedCsv.contains(columnTest.getName()));
|
||||
// CSV quote-escapes values by doubling quotes, so "x" becomes ""x""
|
||||
String csvEscapedTableFqn = tableFqn.replace("\"", "\"\"");
|
||||
String csvEscapedColumnFqn = (tableFqn + ".c1").replace("\"", "\"\"");
|
||||
assertTrue(exportedCsv.contains(csvEscapedTableFqn)); // Should contain table FQN
|
||||
assertTrue(exportedCsv.contains(csvEscapedColumnFqn)); // Should contain column FQN
|
||||
assertResponse(
|
||||
() -> createEntity(create, ADMIN_AUTH_HEADERS),
|
||||
BAD_REQUEST,
|
||||
"Test definition '"
|
||||
+ testDefinition.getName()
|
||||
+ "' is disabled and cannot be used to create test cases");
|
||||
|
||||
// Verify CSV format uses FQN instead of EntityLink
|
||||
assertFalse(exportedCsv.contains("<#E::table::")); // Should not contain EntityLink format
|
||||
// Re-enable the test definition for cleanup using JSON Patch
|
||||
TestDefinition disabled =
|
||||
Entity.getEntity(Entity.TEST_DEFINITION, testDefinition.getId(), "", null);
|
||||
originalJson = JsonUtils.pojoToJson(disabled);
|
||||
disabled.setEnabled(true);
|
||||
updatedJson = JsonUtils.pojoToJson(disabled);
|
||||
|
||||
// Modify the CSV and import it back
|
||||
String modifiedCsv =
|
||||
exportedCsv
|
||||
.replace(tableTest.getDisplayName(), "Modified Table Test")
|
||||
.replace(columnTest.getDescription(), "Modified column test description");
|
||||
|
||||
CsvImportResult result = importCsv(tableFqn, modifiedCsv, false);
|
||||
assertEquals(org.openmetadata.schema.type.ApiStatus.SUCCESS, result.getStatus());
|
||||
assertEquals(3, result.getNumberOfRowsPassed() + result.getNumberOfRowsFailed());
|
||||
|
||||
// Verify the changes were applied
|
||||
TestCase updatedTableTest = getEntity(tableTest.getId(), ADMIN_AUTH_HEADERS);
|
||||
assertEquals("Modified Table Test", updatedTableTest.getDisplayName());
|
||||
|
||||
TestCase updatedColumnTest = getEntity(columnTest.getId(), ADMIN_AUTH_HEADERS);
|
||||
assertEquals("Modified column test description", updatedColumnTest.getDescription());
|
||||
patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
TestUtils.patch(target, patch, TestDefinition.class, ADMIN_AUTH_HEADERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("ImportExport")
|
||||
void testImportExport_TestSuiteLevel(TestInfo test) throws IOException {
|
||||
// Create resource test instances
|
||||
TestSuiteResourceTest testSuiteResourceTest = new TestSuiteResourceTest();
|
||||
TableResourceTest tableResourceTest = new TableResourceTest();
|
||||
void test_existingTestCasesContinueToWork(TestInfo test) throws Exception {
|
||||
// Create a test case with an enabled definition (use table-level test)
|
||||
CreateTestCase create = createRequest(getEntityName(test));
|
||||
create.setEntityLink(TABLE_LINK);
|
||||
create.setTestDefinition(TEST_DEFINITION5.getFullyQualifiedName());
|
||||
create.setParameterValues(
|
||||
List.of(new TestCaseParameterValue().withName("value").withValue("100")));
|
||||
TestCase testCase = createEntity(create, ADMIN_AUTH_HEADERS);
|
||||
assertNotNull(testCase);
|
||||
|
||||
// Create a logical test suite
|
||||
CreateTestSuite createTestSuite =
|
||||
testSuiteResourceTest
|
||||
.createRequest(getEntityName(test))
|
||||
.withDescription("Logical test suite for import/export test");
|
||||
TestSuite testSuite = testSuiteResourceTest.createEntity(createTestSuite, ADMIN_AUTH_HEADERS);
|
||||
// Disable the test definition using JSON Patch
|
||||
String originalJson = JsonUtils.pojoToJson(TEST_DEFINITION5);
|
||||
TEST_DEFINITION5.setEnabled(false);
|
||||
String updatedJson = JsonUtils.pojoToJson(TEST_DEFINITION5);
|
||||
|
||||
// Create tables and test cases
|
||||
Column c1 = new Column().withName("c1").withDataType(BIGINT);
|
||||
CreateTable createTable1 =
|
||||
tableResourceTest.createRequest(test, 1).withColumns(listOf(c1)).withTableConstraints(null);
|
||||
Table table1 = tableResourceTest.createEntity(createTable1, ADMIN_AUTH_HEADERS);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
CreateTable createTable2 =
|
||||
tableResourceTest.createRequest(test, 2).withColumns(listOf(c1)).withTableConstraints(null);
|
||||
Table table2 = tableResourceTest.createEntity(createTable2, ADMIN_AUTH_HEADERS);
|
||||
WebTarget target =
|
||||
getResource("dataQuality/testDefinitions").path(TEST_DEFINITION5.getId().toString());
|
||||
TestUtils.patch(target, patch, TestDefinition.class, ADMIN_AUTH_HEADERS);
|
||||
|
||||
// Get test definition
|
||||
TestDefinition tableRowCountDef =
|
||||
Entity.getEntityByName(
|
||||
TEST_DEFINITION, "tableRowCountToBeBetween", "", Include.NON_DELETED);
|
||||
// Existing test case should still be retrievable
|
||||
TestCase retrieved = getEntity(testCase.getId(), ADMIN_AUTH_HEADERS);
|
||||
assertNotNull(retrieved);
|
||||
assertEquals(testCase.getId(), retrieved.getId());
|
||||
|
||||
// Create test cases in the logical test suite
|
||||
CreateTestCase createTest1 =
|
||||
createRequest(getEntityName(test, 1))
|
||||
.withEntityLink(String.format("<#E::table::%s>", table1.getFullyQualifiedName()))
|
||||
.withTestDefinition(tableRowCountDef.getFullyQualifiedName())
|
||||
.withParameterValues(
|
||||
listOf(
|
||||
new TestCaseParameterValue().withName("minValue").withValue("10"),
|
||||
new TestCaseParameterValue().withName("maxValue").withValue("100")));
|
||||
// Should be able to update the existing test case
|
||||
String oldDescription = testCase.getDescription();
|
||||
String updatedDescription = "Updated description for existing test case";
|
||||
String json = JsonUtils.pojoToJson(testCase);
|
||||
testCase.setDescription(updatedDescription);
|
||||
ChangeDescription change = getChangeDescription(testCase, MINOR_UPDATE);
|
||||
fieldUpdated(change, "description", oldDescription, updatedDescription);
|
||||
patchEntityAndCheck(testCase, json, ADMIN_AUTH_HEADERS, MINOR_UPDATE, change);
|
||||
|
||||
CreateTestCase createTest2 =
|
||||
createRequest(getEntityName(test, 2))
|
||||
.withEntityLink(String.format("<#E::table::%s>", table2.getFullyQualifiedName()))
|
||||
.withTestDefinition(tableRowCountDef.getFullyQualifiedName())
|
||||
.withParameterValues(
|
||||
listOf(
|
||||
new TestCaseParameterValue().withName("minValue").withValue("5"),
|
||||
new TestCaseParameterValue().withName("maxValue").withValue("50")));
|
||||
// Re-enable the test definition for cleanup using JSON Patch
|
||||
TestDefinition disabled =
|
||||
Entity.getEntity(Entity.TEST_DEFINITION, TEST_DEFINITION5.getId(), "", null);
|
||||
originalJson = JsonUtils.pojoToJson(disabled);
|
||||
disabled.setEnabled(true);
|
||||
updatedJson = JsonUtils.pojoToJson(disabled);
|
||||
|
||||
TestCase test1 = createEntity(createTest1, ADMIN_AUTH_HEADERS);
|
||||
TestCase test2 = createEntity(createTest2, ADMIN_AUTH_HEADERS);
|
||||
|
||||
// Add test cases to logical test suite using the existing endpoint
|
||||
addTestCasesToLogicalTestSuiteViaAPI(testSuite.getId(), listOf(test1.getId(), test2.getId()));
|
||||
|
||||
// Export test cases from the test suite
|
||||
String exportedCsv = exportCsv(testSuite.getFullyQualifiedName());
|
||||
assertNotNull(exportedCsv);
|
||||
assertTrue(exportedCsv.contains(test1.getName()));
|
||||
assertTrue(exportedCsv.contains(test2.getName()));
|
||||
|
||||
// Import modified CSV
|
||||
String modifiedCsv = exportedCsv.replace("10", "20").replace("100", "200");
|
||||
CsvImportResult result = importCsv(testSuite.getFullyQualifiedName(), modifiedCsv, false);
|
||||
LOG.info("Import result status: {}", result.getStatus());
|
||||
LOG.info("Import result CSV:\n{}", result.getImportResultsCsv());
|
||||
assertEquals(org.openmetadata.schema.type.ApiStatus.SUCCESS, result.getStatus());
|
||||
|
||||
// Verify parameter values were updated
|
||||
TestCase updatedTest1 = getEntity(test1.getId(), ADMIN_AUTH_HEADERS);
|
||||
assertEquals(
|
||||
"20",
|
||||
updatedTest1.getParameterValues().stream()
|
||||
.filter(p -> p.getName().equals("minValue"))
|
||||
.findFirst()
|
||||
.get()
|
||||
.getValue());
|
||||
patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
TestUtils.patch(target, patch, TestDefinition.class, ADMIN_AUTH_HEADERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("ImportExport")
|
||||
void testImportExport_PlatformWide(TestInfo test) throws IOException {
|
||||
// Create multiple tables and test cases
|
||||
TableResourceTest tableResourceTest = new TableResourceTest();
|
||||
Column c1 = new Column().withName("c1").withDataType(BIGINT);
|
||||
CreateTable createTable1 =
|
||||
tableResourceTest.createRequest(test, 1).withColumns(listOf(c1)).withTableConstraints(null);
|
||||
Table table1 = tableResourceTest.createEntity(createTable1, ADMIN_AUTH_HEADERS);
|
||||
void test_cannotCreateNewTestCaseWhenDefinitionDisabled(TestInfo test) throws Exception {
|
||||
// Create a test case with an enabled definition (use table-level test)
|
||||
CreateTestCase create1 = createRequest(getEntityName(test) + "_1");
|
||||
create1.setEntityLink(TABLE_LINK);
|
||||
create1.setTestDefinition(TEST_DEFINITION4.getFullyQualifiedName());
|
||||
create1.setParameterValues(
|
||||
List.of(
|
||||
new TestCaseParameterValue().withName("minValue").withValue("10"),
|
||||
new TestCaseParameterValue().withName("maxValue").withValue("100")));
|
||||
TestCase testCase1 = createEntity(create1, ADMIN_AUTH_HEADERS);
|
||||
assertNotNull(testCase1);
|
||||
|
||||
CreateTable createTable2 =
|
||||
tableResourceTest.createRequest(test, 2).withColumns(listOf(c1)).withTableConstraints(null);
|
||||
Table table2 = tableResourceTest.createEntity(createTable2, ADMIN_AUTH_HEADERS);
|
||||
// Disable the test definition using JSON Patch
|
||||
String originalJson = JsonUtils.pojoToJson(TEST_DEFINITION4);
|
||||
TEST_DEFINITION4.setEnabled(false);
|
||||
String updatedJson = JsonUtils.pojoToJson(TEST_DEFINITION4);
|
||||
|
||||
// Get test definition
|
||||
TestDefinition tableRowCountDef =
|
||||
Entity.getEntityByName(
|
||||
TEST_DEFINITION, "tableRowCountToBeBetween", "", Include.NON_DELETED);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
// Create test cases
|
||||
CreateTestCase createTest1 =
|
||||
createRequest(getEntityName(test, 1))
|
||||
.withEntityLink(String.format("<#E::table::%s>", table1.getFullyQualifiedName()))
|
||||
.withTestDefinition(tableRowCountDef.getFullyQualifiedName())
|
||||
.withParameterValues(
|
||||
listOf(
|
||||
new TestCaseParameterValue().withName("minValue").withValue("10"),
|
||||
new TestCaseParameterValue().withName("maxValue").withValue("100")));
|
||||
WebTarget target =
|
||||
getResource("dataQuality/testDefinitions").path(TEST_DEFINITION4.getId().toString());
|
||||
TestUtils.patch(target, patch, TestDefinition.class, ADMIN_AUTH_HEADERS);
|
||||
|
||||
CreateTestCase createTest2 =
|
||||
createRequest(getEntityName(test, 2))
|
||||
.withEntityLink(String.format("<#E::table::%s>", table2.getFullyQualifiedName()))
|
||||
.withTestDefinition(tableRowCountDef.getFullyQualifiedName())
|
||||
.withParameterValues(
|
||||
listOf(
|
||||
new TestCaseParameterValue().withName("minValue").withValue("5"),
|
||||
new TestCaseParameterValue().withName("maxValue").withValue("50")));
|
||||
// Try to create another test case with the disabled definition - should fail
|
||||
CreateTestCase create2 = createRequest(getEntityName(test) + "_2");
|
||||
create2.setEntityLink(TABLE_LINK);
|
||||
create2.setTestDefinition(TEST_DEFINITION4.getFullyQualifiedName());
|
||||
create2.setParameterValues(
|
||||
List.of(
|
||||
new TestCaseParameterValue().withName("minValue").withValue("10"),
|
||||
new TestCaseParameterValue().withName("maxValue").withValue("100")));
|
||||
|
||||
TestCase test1 = createEntity(createTest1, ADMIN_AUTH_HEADERS);
|
||||
TestCase test2 = createEntity(createTest2, ADMIN_AUTH_HEADERS);
|
||||
assertResponse(
|
||||
() -> createEntity(create2, ADMIN_AUTH_HEADERS),
|
||||
BAD_REQUEST,
|
||||
"Test definition '"
|
||||
+ TEST_DEFINITION4.getName()
|
||||
+ "' is disabled and cannot be used to create test cases");
|
||||
|
||||
// Export all test cases platform-wide using "*"
|
||||
String exportedCsv = exportCsv("*");
|
||||
assertNotNull(exportedCsv);
|
||||
// Re-enable the test definition for cleanup using JSON Patch
|
||||
TestDefinition disabled =
|
||||
Entity.getEntity(Entity.TEST_DEFINITION, TEST_DEFINITION4.getId(), "", null);
|
||||
originalJson = JsonUtils.pojoToJson(disabled);
|
||||
disabled.setEnabled(true);
|
||||
updatedJson = JsonUtils.pojoToJson(disabled);
|
||||
|
||||
// Verify exported CSV contains test cases from multiple tables
|
||||
assertTrue(exportedCsv.contains(test1.getName()));
|
||||
assertTrue(exportedCsv.contains(test2.getName()));
|
||||
|
||||
// Count number of test cases in export (excluding header)
|
||||
long testCaseCount = exportedCsv.lines().count() - 1;
|
||||
assertTrue(testCaseCount >= 2, "Should export at least 2 test cases");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("ImportExport")
|
||||
void testImportCsv_CreateAndUpdate(TestInfo test) throws IOException {
|
||||
TableResourceTest tableResourceTest = new TableResourceTest();
|
||||
Column c1 = new Column().withName("c1").withDataType(BIGINT);
|
||||
CreateTable createTable =
|
||||
tableResourceTest.createRequest(test).withColumns(listOf(c1)).withTableConstraints(null);
|
||||
Table table = tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
|
||||
|
||||
// Get test definition
|
||||
TestDefinition tableRowCountDef =
|
||||
Entity.getEntityByName(
|
||||
TEST_DEFINITION, "tableRowCountToBeBetween", "", Include.NON_DELETED);
|
||||
|
||||
// Escape quotes in FQN for CSV format (double the quotes and wrap in quotes)
|
||||
String entityFQN = "\"" + table.getFullyQualifiedName().replace("\"", "\"\"") + "\"";
|
||||
|
||||
// Test 1: Create a new test case via CSV import with tags
|
||||
// Properly escape parameter values for CSV - double the quotes and wrap in quotes
|
||||
String paramValues1 =
|
||||
"\"{\"\"name\"\":\"\"minValue\"\",\"\"value\"\":10};{\"\"name\"\":\"\"maxValue\"\",\"\"value\"\":100}\"";
|
||||
String createCsv =
|
||||
"name*,displayName,description,testDefinition*,entityFQN*,testSuite,parameterValues,computePassedFailedRowCount,useDynamicAssertion,inspectionQuery,tags,glossaryTerms\n"
|
||||
+ String.format(
|
||||
"%s,New Test Case,Initial description,%s,%s,,%s,false,false,,PII.Sensitive,",
|
||||
getEntityName(test),
|
||||
tableRowCountDef.getFullyQualifiedName(),
|
||||
entityFQN,
|
||||
paramValues1);
|
||||
|
||||
CsvImportResult createResult = importCsv(table.getFullyQualifiedName(), createCsv, false);
|
||||
LOG.info("Create import status: {}", createResult.getStatus());
|
||||
LOG.info("Create import result:\n{}", createResult.getImportResultsCsv());
|
||||
assertEquals(org.openmetadata.schema.type.ApiStatus.SUCCESS, createResult.getStatus());
|
||||
// Note: NumberOfRowsPassed includes the header row, so 1 data row = 2 total
|
||||
assertEquals(2, createResult.getNumberOfRowsPassed());
|
||||
|
||||
// Verify test case was created with tags
|
||||
String testCaseFqn =
|
||||
FullyQualifiedName.add(
|
||||
table.getFullyQualifiedName(), EntityInterfaceUtil.quoteName(getEntityName(test)));
|
||||
TestCase created = getEntityByName(testCaseFqn, "tags", ADMIN_AUTH_HEADERS);
|
||||
assertNotNull(created);
|
||||
assertEquals("New Test Case", created.getDisplayName());
|
||||
assertEquals("Initial description", created.getDescription());
|
||||
assertEquals(2, created.getParameterValues().size());
|
||||
assertNotNull(created.getTags());
|
||||
assertEquals(1, created.getTags().size());
|
||||
assertEquals("PII.Sensitive", created.getTags().get(0).getTagFQN());
|
||||
|
||||
// Test 2: Update the existing test case via CSV import with different tags
|
||||
String paramValues2 =
|
||||
"\"{\"\"name\"\":\"\"minValue\"\",\"\"value\"\":5};{\"\"name\"\":\"\"maxValue\"\",\"\"value\"\":50}\"";
|
||||
String updateCsv =
|
||||
"name*,displayName,description,testDefinition*,entityFQN*,testSuite,parameterValues,computePassedFailedRowCount,useDynamicAssertion,inspectionQuery,tags,glossaryTerms\n"
|
||||
+ String.format(
|
||||
"%s,Updated Test Case,Updated description,%s,%s,,%s,true,false,SELECT * FROM table,PersonalData.Personal,",
|
||||
getEntityName(test),
|
||||
tableRowCountDef.getFullyQualifiedName(),
|
||||
entityFQN,
|
||||
paramValues2);
|
||||
|
||||
CsvImportResult updateResult = importCsv(table.getFullyQualifiedName(), updateCsv, false);
|
||||
LOG.info("Update import status: {}", updateResult.getStatus());
|
||||
LOG.info("Update import result:\n{}", updateResult.getImportResultsCsv());
|
||||
assertEquals(org.openmetadata.schema.type.ApiStatus.SUCCESS, updateResult.getStatus());
|
||||
// Note: NumberOfRowsPassed includes the header row, so 1 data row = 2 total
|
||||
assertEquals(2, updateResult.getNumberOfRowsPassed());
|
||||
|
||||
// Verify test case was updated with new tags
|
||||
TestCase updated = getEntityByName(testCaseFqn, "tags", ADMIN_AUTH_HEADERS);
|
||||
assertNotNull(updated);
|
||||
assertEquals("Updated Test Case", updated.getDisplayName());
|
||||
assertEquals("Updated description", updated.getDescription());
|
||||
assertEquals(2, updated.getParameterValues().size());
|
||||
assertEquals("5", updated.getParameterValues().get(0).getValue());
|
||||
assertEquals(true, updated.getComputePassedFailedRowCount());
|
||||
assertEquals("SELECT * FROM table", updated.getInspectionQuery());
|
||||
assertNotNull(updated.getTags());
|
||||
assertEquals(1, updated.getTags().size());
|
||||
assertEquals("PersonalData.Personal", updated.getTags().get(0).getTagFQN());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("ImportExport")
|
||||
void testImportCsv_DryRun(TestInfo test) throws IOException {
|
||||
TableResourceTest tableResourceTest = new TableResourceTest();
|
||||
Column c1 = new Column().withName("c1").withDataType(BIGINT);
|
||||
CreateTable createTable =
|
||||
tableResourceTest.createRequest(test).withColumns(listOf(c1)).withTableConstraints(null);
|
||||
Table table = tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
|
||||
|
||||
// Get test definition
|
||||
TestDefinition tableRowCountDef =
|
||||
Entity.getEntityByName(
|
||||
TEST_DEFINITION, "tableRowCountToBeBetween", "", Include.NON_DELETED);
|
||||
|
||||
// Escape quotes in FQN for CSV format (double the quotes and wrap in quotes)
|
||||
String entityFQN = "\"" + table.getFullyQualifiedName().replace("\"", "\"\"") + "\"";
|
||||
// Headers with * for required fields (name, testDefinition, entityFQN are required)
|
||||
String csv =
|
||||
"name*,displayName,description,testDefinition*,entityFQN*,testSuite,parameterValues,computePassedFailedRowCount,useDynamicAssertion,inspectionQuery,tags,glossaryTerms\n"
|
||||
+ String.format(
|
||||
"%s,Dry run test,Test description,%s,%s,,,false,false,,,",
|
||||
getEntityName(test), tableRowCountDef.getFullyQualifiedName(), entityFQN);
|
||||
|
||||
// Dry run should not create the entity
|
||||
CsvImportResult dryRunResult = importCsv(table.getFullyQualifiedName(), csv, true);
|
||||
if (dryRunResult.getStatus() != org.openmetadata.schema.type.ApiStatus.SUCCESS) {
|
||||
LOG.info("Dry run import status: {}", dryRunResult.getStatus());
|
||||
LOG.info("Dry run abort reason: {}", dryRunResult.getAbortReason());
|
||||
LOG.info("Dry run import result:\n{}", dryRunResult.getImportResultsCsv());
|
||||
}
|
||||
assertEquals(org.openmetadata.schema.type.ApiStatus.SUCCESS, dryRunResult.getStatus());
|
||||
assertTrue(dryRunResult.getDryRun());
|
||||
|
||||
// Verify entity was not created - use FQN which includes entityFQN + test case name
|
||||
String testCaseFqn =
|
||||
FullyQualifiedName.add(
|
||||
table.getFullyQualifiedName(), EntityInterfaceUtil.quoteName(getEntityName(test)));
|
||||
assertThrows(
|
||||
HttpResponseException.class, () -> getEntityByName(testCaseFqn, ADMIN_AUTH_HEADERS));
|
||||
|
||||
// Actual import should create the entity
|
||||
CsvImportResult actualResult = importCsv(table.getFullyQualifiedName(), csv, false);
|
||||
LOG.info("Actual import status: {}", actualResult.getStatus());
|
||||
LOG.info("Actual import result:\n{}", actualResult.getImportResultsCsv());
|
||||
assertEquals(org.openmetadata.schema.type.ApiStatus.SUCCESS, actualResult.getStatus());
|
||||
assertFalse(actualResult.getDryRun());
|
||||
|
||||
// Verify entity was created
|
||||
TestCase created = getEntityByName(testCaseFqn, ADMIN_AUTH_HEADERS);
|
||||
assertNotNull(created);
|
||||
assertEquals("Dry run test", created.getDisplayName());
|
||||
}
|
||||
|
||||
private void addTestCasesToLogicalTestSuiteViaAPI(UUID testSuiteId, List<UUID> testCaseIds)
|
||||
throws HttpResponseException {
|
||||
CreateLogicalTestCases createLogicalTestCases =
|
||||
new CreateLogicalTestCases().withTestSuiteId(testSuiteId).withTestCaseIds(testCaseIds);
|
||||
WebTarget target = getCollection().path("/logicalTestCases");
|
||||
org.openmetadata.service.util.TestUtils.put(
|
||||
target, createLogicalTestCases, TestSuite.class, OK, ADMIN_AUTH_HEADERS);
|
||||
patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
TestUtils.patch(target, patch, TestDefinition.class, ADMIN_AUTH_HEADERS);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
package org.openmetadata.service.resources.dqtests;
|
||||
|
||||
import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST;
|
||||
import static jakarta.ws.rs.core.Response.Status.FORBIDDEN;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.openmetadata.service.exception.CatalogExceptionMessage.permissionNotAllowed;
|
||||
import static org.openmetadata.service.util.TestUtils.ADMIN_AUTH_HEADERS;
|
||||
import static org.openmetadata.service.util.TestUtils.TEST_AUTH_HEADERS;
|
||||
import static org.openmetadata.service.util.TestUtils.TEST_USER_NAME;
|
||||
import static org.openmetadata.service.util.TestUtils.assertListNotNull;
|
||||
import static org.openmetadata.service.util.TestUtils.assertListNull;
|
||||
import static org.openmetadata.service.util.TestUtils.assertResponse;
|
||||
import static org.openmetadata.service.util.TestUtils.assertResponseContains;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.flipkart.zjsonpatch.JsonDiff;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -22,7 +29,9 @@ import org.openmetadata.schema.tests.TestCaseParameter;
|
|||
import org.openmetadata.schema.tests.TestDefinition;
|
||||
import org.openmetadata.schema.tests.TestPlatform;
|
||||
import org.openmetadata.schema.type.ColumnDataType;
|
||||
import org.openmetadata.schema.type.MetadataOperation;
|
||||
import org.openmetadata.schema.type.TestDefinitionEntityType;
|
||||
import org.openmetadata.schema.utils.JsonUtils;
|
||||
import org.openmetadata.schema.utils.ResultList;
|
||||
import org.openmetadata.service.Entity;
|
||||
import org.openmetadata.service.resources.EntityResourceTest;
|
||||
|
|
@ -222,4 +231,274 @@ public class TestDefinitionResourceTest
|
|||
public void assertFieldChange(String fieldName, Object expected, Object actual) {
|
||||
assertCommonFieldChange(fieldName, expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_enableDisableTestDefinition(TestInfo test) throws Exception {
|
||||
// Create a test definition
|
||||
TestDefinition testDef = createEntity(createRequest(test), ADMIN_AUTH_HEADERS);
|
||||
assertEquals(true, testDef.getEnabled(), "Test definition should be enabled by default");
|
||||
|
||||
// Disable it using JSON Patch
|
||||
String originalJson = JsonUtils.pojoToJson(testDef);
|
||||
testDef.setEnabled(false);
|
||||
String updatedJson = JsonUtils.pojoToJson(testDef);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
TestDefinition disabled = patchEntity(testDef.getId(), patch, ADMIN_AUTH_HEADERS);
|
||||
assertEquals(false, disabled.getEnabled(), "Test definition should be disabled");
|
||||
|
||||
// Verify disabled state persists
|
||||
TestDefinition retrieved = getEntity(testDef.getId(), ADMIN_AUTH_HEADERS);
|
||||
assertEquals(false, retrieved.getEnabled(), "Test definition should remain disabled");
|
||||
|
||||
// Enable it back using JSON Patch
|
||||
originalJson = JsonUtils.pojoToJson(retrieved);
|
||||
retrieved.setEnabled(true);
|
||||
updatedJson = JsonUtils.pojoToJson(retrieved);
|
||||
|
||||
patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
TestDefinition enabled = patchEntity(retrieved.getId(), patch, ADMIN_AUTH_HEADERS);
|
||||
assertEquals(true, enabled.getEnabled(), "Test definition should be enabled");
|
||||
|
||||
// Verify enabled state persists
|
||||
retrieved = getEntity(testDef.getId(), ADMIN_AUTH_HEADERS);
|
||||
assertEquals(true, retrieved.getEnabled(), "Test definition should remain enabled");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_defaultEnabledTrue(TestInfo test) throws HttpResponseException {
|
||||
// Create test definition without specifying enabled field
|
||||
TestDefinition testDef = createEntity(createRequest(test), ADMIN_AUTH_HEADERS);
|
||||
assertEquals(true, testDef.getEnabled(), "Test definition should default to enabled=true");
|
||||
|
||||
// Verify via GET as well
|
||||
TestDefinition retrieved = getEntity(testDef.getId(), ADMIN_AUTH_HEADERS);
|
||||
assertEquals(true, retrieved.getEnabled(), "Retrieved test definition should be enabled");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_systemTestDefinitionCanBeDisabled(TestInfo test) throws Exception {
|
||||
// Get a system test definition
|
||||
TestDefinition systemDef = getEntityByName("columnValuesToBeNotNull", "", ADMIN_AUTH_HEADERS);
|
||||
assertEquals(
|
||||
true, systemDef.getEnabled(), "System test definition should be enabled by default");
|
||||
|
||||
// Disable system test definition using JSON Patch
|
||||
String originalJson = JsonUtils.pojoToJson(systemDef);
|
||||
systemDef.setEnabled(false);
|
||||
String updatedJson = JsonUtils.pojoToJson(systemDef);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
TestDefinition disabled = patchEntity(systemDef.getId(), patch, ADMIN_AUTH_HEADERS);
|
||||
assertEquals(false, disabled.getEnabled(), "System test definition should be disableable");
|
||||
|
||||
// Re-enable for cleanup using JSON Patch
|
||||
originalJson = JsonUtils.pojoToJson(disabled);
|
||||
disabled.setEnabled(true);
|
||||
updatedJson = JsonUtils.pojoToJson(disabled);
|
||||
|
||||
patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
patchEntity(disabled.getId(), patch, ADMIN_AUTH_HEADERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_listTestDefinitions_filterByEnabled(TestInfo test) throws Exception {
|
||||
// Create two test definitions
|
||||
TestDefinition enabledDef = createEntity(createRequest(test, 1), ADMIN_AUTH_HEADERS);
|
||||
TestDefinition toDisableDef = createEntity(createRequest(test, 2), ADMIN_AUTH_HEADERS);
|
||||
|
||||
// Disable the second one using JSON Patch
|
||||
String originalJson = JsonUtils.pojoToJson(toDisableDef);
|
||||
toDisableDef.setEnabled(false);
|
||||
String updatedJson = JsonUtils.pojoToJson(toDisableDef);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
TestDefinition disabledDef = patchEntity(toDisableDef.getId(), patch, ADMIN_AUTH_HEADERS);
|
||||
assertEquals(false, disabledDef.getEnabled(), "Test definition should be disabled");
|
||||
|
||||
// Test 1: enabled=true should return only enabled test definitions
|
||||
Map<String, String> enabledTrueParams = Map.of("limit", "1000", "enabled", "true");
|
||||
ResultList<TestDefinition> enabledList = listEntities(enabledTrueParams, ADMIN_AUTH_HEADERS);
|
||||
boolean hasEnabled =
|
||||
enabledList.getData().stream().anyMatch(td -> td.getId().equals(enabledDef.getId()));
|
||||
boolean hasDisabled =
|
||||
enabledList.getData().stream().anyMatch(td -> td.getId().equals(disabledDef.getId()));
|
||||
Assertions.assertTrue(hasEnabled, "enabled=true list should include enabled test definition");
|
||||
Assertions.assertFalse(
|
||||
hasDisabled, "enabled=true list should NOT include disabled test definition");
|
||||
|
||||
// Verify all enabled definitions in the enabled list are actually enabled
|
||||
boolean allEnabled =
|
||||
enabledList.getData().stream()
|
||||
.allMatch(td -> td.getEnabled() == null || Boolean.TRUE.equals(td.getEnabled()));
|
||||
Assertions.assertTrue(
|
||||
allEnabled, "All test definitions in enabled=true list should be enabled");
|
||||
|
||||
// Test 2: enabled=false should return only disabled test definitions
|
||||
Map<String, String> enabledFalseParams = Map.of("limit", "1000", "enabled", "false");
|
||||
ResultList<TestDefinition> disabledList = listEntities(enabledFalseParams, ADMIN_AUTH_HEADERS);
|
||||
hasEnabled =
|
||||
disabledList.getData().stream().anyMatch(td -> td.getId().equals(enabledDef.getId()));
|
||||
hasDisabled =
|
||||
disabledList.getData().stream().anyMatch(td -> td.getId().equals(disabledDef.getId()));
|
||||
Assertions.assertFalse(
|
||||
hasEnabled, "enabled=false list should NOT include enabled test definition");
|
||||
Assertions.assertTrue(
|
||||
hasDisabled, "enabled=false list should include disabled test definition");
|
||||
|
||||
// Verify all disabled definitions in the disabled list are actually disabled
|
||||
boolean allDisabled =
|
||||
disabledList.getData().stream().allMatch(td -> Boolean.FALSE.equals(td.getEnabled()));
|
||||
Assertions.assertTrue(
|
||||
allDisabled, "All test definitions in enabled=false list should be disabled");
|
||||
|
||||
// Test 3: Default behavior (no enabled param) should return all test definitions
|
||||
Map<String, String> defaultParams = Map.of("limit", "1000");
|
||||
ResultList<TestDefinition> defaultList = listEntities(defaultParams, ADMIN_AUTH_HEADERS);
|
||||
hasEnabled =
|
||||
defaultList.getData().stream().anyMatch(td -> td.getId().equals(enabledDef.getId()));
|
||||
hasDisabled =
|
||||
defaultList.getData().stream().anyMatch(td -> td.getId().equals(disabledDef.getId()));
|
||||
Assertions.assertTrue(hasEnabled, "Default list should include enabled test definition");
|
||||
Assertions.assertTrue(hasDisabled, "Default list should include disabled test definition");
|
||||
|
||||
// Re-enable for cleanup using JSON Patch
|
||||
originalJson = JsonUtils.pojoToJson(disabledDef);
|
||||
disabledDef.setEnabled(true);
|
||||
updatedJson = JsonUtils.pojoToJson(disabledDef);
|
||||
|
||||
patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
patchEntity(disabledDef.getId(), patch, ADMIN_AUTH_HEADERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_createTestDefinition_asNonAdmin_403() {
|
||||
// Non-admin user without CREATE permission should not be able to create test definition
|
||||
CreateTestDefinition create = createRequest("unauthorizedTestDef");
|
||||
assertResponse(
|
||||
() -> createEntity(create, TEST_AUTH_HEADERS),
|
||||
FORBIDDEN,
|
||||
permissionNotAllowed(TEST_USER_NAME, List.of(MetadataOperation.CREATE)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_patchTestDefinition_asNonAdmin_403(TestInfo test) throws Exception {
|
||||
// Create a test definition as admin
|
||||
TestDefinition testDef = createEntity(createRequest(test), ADMIN_AUTH_HEADERS);
|
||||
|
||||
// Try to patch (enable/disable) as non-admin user
|
||||
String originalJson = JsonUtils.pojoToJson(testDef);
|
||||
testDef.setEnabled(false);
|
||||
String updatedJson = JsonUtils.pojoToJson(testDef);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
// Non-admin user without EDIT_ALL permission should not be able to patch
|
||||
assertResponse(
|
||||
() -> patchEntity(testDef.getId(), patch, TEST_AUTH_HEADERS),
|
||||
FORBIDDEN,
|
||||
permissionNotAllowed(TEST_USER_NAME, List.of(MetadataOperation.EDIT_ALL)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_deleteTestDefinition_asNonAdmin_403(TestInfo test) throws HttpResponseException {
|
||||
// Create a test definition as admin
|
||||
TestDefinition testDef = createEntity(createRequest(test), ADMIN_AUTH_HEADERS);
|
||||
|
||||
// Non-admin user without DELETE permission should not be able to delete
|
||||
assertResponse(
|
||||
() -> deleteEntity(testDef.getId(), TEST_AUTH_HEADERS),
|
||||
FORBIDDEN,
|
||||
permissionNotAllowed(TEST_USER_NAME, List.of(MetadataOperation.DELETE)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_systemTestDefinitionCannotModifyEntityType(TestInfo test) throws Exception {
|
||||
// Get a system test definition
|
||||
TestDefinition systemDef = getEntityByName("columnValuesToBeNotNull", "", ADMIN_AUTH_HEADERS);
|
||||
assertEquals(
|
||||
org.openmetadata.schema.type.ProviderType.SYSTEM,
|
||||
systemDef.getProvider(),
|
||||
"Should be a system test definition");
|
||||
|
||||
// Try to modify entity type using JSON Patch - should fail
|
||||
String originalJson = JsonUtils.pojoToJson(systemDef);
|
||||
systemDef.setEntityType(TestDefinitionEntityType.TABLE);
|
||||
String updatedJson = JsonUtils.pojoToJson(systemDef);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
assertResponse(
|
||||
() -> patchEntity(systemDef.getId(), patch, ADMIN_AUTH_HEADERS),
|
||||
BAD_REQUEST,
|
||||
"System test definitions cannot have their entity type modified");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_systemTestDefinitionCannotBeDeleted(TestInfo test) throws HttpResponseException {
|
||||
// Get a system test definition
|
||||
TestDefinition systemDef = getEntityByName("columnValuesToBeNotNull", "", ADMIN_AUTH_HEADERS);
|
||||
assertEquals(
|
||||
org.openmetadata.schema.type.ProviderType.SYSTEM,
|
||||
systemDef.getProvider(),
|
||||
"Should be a system test definition");
|
||||
|
||||
// Try to delete the system test definition - should fail
|
||||
assertResponse(
|
||||
() -> deleteEntity(systemDef.getId(), ADMIN_AUTH_HEADERS),
|
||||
BAD_REQUEST,
|
||||
"System entity [columnValuesToBeNotNull] of type testDefinition can not be deleted.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_userTestDefinitionCanBeModified(TestInfo test) throws Exception {
|
||||
// Create a user test definition
|
||||
TestDefinition userDef = createEntity(createRequest(test), ADMIN_AUTH_HEADERS);
|
||||
assertEquals(
|
||||
org.openmetadata.schema.type.ProviderType.USER,
|
||||
userDef.getProvider(),
|
||||
"Should be a user test definition");
|
||||
|
||||
// Modify entity type using JSON Patch - should succeed
|
||||
String originalJson = JsonUtils.pojoToJson(userDef);
|
||||
userDef.setEntityType(TestDefinitionEntityType.TABLE);
|
||||
String updatedJson = JsonUtils.pojoToJson(userDef);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode patch = JsonDiff.asJson(mapper.readTree(originalJson), mapper.readTree(updatedJson));
|
||||
|
||||
TestDefinition modified = patchEntity(userDef.getId(), patch, ADMIN_AUTH_HEADERS);
|
||||
assertEquals(
|
||||
TestDefinitionEntityType.TABLE,
|
||||
modified.getEntityType(),
|
||||
"User test definition entity type should be modifiable");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_userTestDefinitionCanBeDeleted(TestInfo test) throws HttpResponseException {
|
||||
// Create a user test definition
|
||||
TestDefinition userDef = createEntity(createRequest(test), ADMIN_AUTH_HEADERS);
|
||||
assertEquals(
|
||||
org.openmetadata.schema.type.ProviderType.USER,
|
||||
userDef.getProvider(),
|
||||
"Should be a user test definition");
|
||||
|
||||
// Delete the user test definition - should succeed
|
||||
deleteEntity(userDef.getId(), ADMIN_AUTH_HEADERS);
|
||||
|
||||
// Verify it's deleted
|
||||
assertResponseContains(
|
||||
() -> getEntity(userDef.getId(), ADMIN_AUTH_HEADERS),
|
||||
jakarta.ws.rs.core.Response.Status.NOT_FOUND,
|
||||
"not found");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@
|
|||
"$ref": "../../tests/testDefinition.json#/definitions/testCaseParameterDefinition"
|
||||
}
|
||||
},
|
||||
"dataQualityDimension": {
|
||||
"$ref": "../../tests/testDefinition.json#/definitions/dataQualityDimensions"
|
||||
},
|
||||
"supportedServices": {
|
||||
"description": "List of services that this test definition supports. When empty, it implies all services are supported.",
|
||||
"type": "array",
|
||||
|
|
@ -61,6 +64,10 @@
|
|||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"sqlExpression": {
|
||||
"description": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters.",
|
||||
"$ref": "../../type/basic.json#/definitions/sqlQuery"
|
||||
}
|
||||
},
|
||||
"required": ["name", "description","entityType", "testPlatforms"],
|
||||
|
|
|
|||
|
|
@ -65,7 +65,9 @@
|
|||
"DeleteScim",
|
||||
"ViewScim",
|
||||
"Impersonate",
|
||||
"AuditLogs"
|
||||
"AuditLogs",
|
||||
"ViewTestDefinitionLibrary",
|
||||
"EditTestDefinitionLibrary"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -217,6 +217,11 @@
|
|||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"enabled": {
|
||||
"description": "When `true` indicates the test definition is available for creating test cases. System test definitions can only be disabled by users with appropriate permissions.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"supportedServices": {
|
||||
"description": "List of services that this test definition supports. When empty, it implies all services are supported.",
|
||||
"type": "array",
|
||||
|
|
@ -224,6 +229,10 @@
|
|||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"sqlExpression": {
|
||||
"description": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"$ref": "../type/basic.json#/definitions/sqlQuery"
|
||||
}
|
||||
},
|
||||
"required": ["name", "description", "testPlatforms"],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,520 @@
|
|||
/*
|
||||
* Copyright 2024 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 test, { expect } from '@playwright/test';
|
||||
import { redirectToHomePage, uuid } from '../../../utils/common';
|
||||
|
||||
|
||||
const TEST_DEFINITION_NAME = `aCustomTestDefinition${uuid()}`;
|
||||
const TEST_DEFINITION_DISPLAY_NAME = `Custom Test Definition ${uuid()}`;
|
||||
const UPDATE_TEST_DEFINITION_DISPLAY_NAME = `Updated Custom Test Definition ${uuid()}`;
|
||||
const TEST_DEFINITION_DESCRIPTION =
|
||||
'A This is a custom test definition for E2E testing';
|
||||
|
||||
test.use({ storageState: 'playwright/.auth/admin.json' });
|
||||
|
||||
test.describe('Rules Library', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await redirectToHomePage(page);
|
||||
});
|
||||
|
||||
test('should navigate to Rules Library page', async ({ page }) => {
|
||||
// Navigate directly to Rules Library
|
||||
await page.goto('/rules-library');
|
||||
|
||||
// Wait for page to load
|
||||
await page.waitForSelector('[data-testid="test-definition-table"]', {
|
||||
state: 'visible',
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
// Verify URL
|
||||
await expect(page).toHaveURL(/.*\/rules-library/);
|
||||
});
|
||||
|
||||
test('should display test definitions table with columns', async ({
|
||||
page,
|
||||
}) => {
|
||||
// Navigate to Rules Library and wait for response
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'GET'
|
||||
);
|
||||
|
||||
await page.goto('/rules-library');
|
||||
await responsePromise;
|
||||
|
||||
// Verify table is displayed
|
||||
await expect(page.getByTestId('test-definition-table')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should display system test definitions', async ({ page }) => {
|
||||
// Wait for API response before navigation
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'GET'
|
||||
);
|
||||
|
||||
await page.goto('/rules-library');
|
||||
await responsePromise;
|
||||
|
||||
// Verify at least one test definition is displayed
|
||||
const testDefinitionRows = page.locator(
|
||||
'[data-testid="test-definition-table"] tbody tr'
|
||||
);
|
||||
|
||||
await expect(testDefinitionRows).not.toHaveCount(0);
|
||||
});
|
||||
|
||||
test('should create, edit, and delete a test definition', async ({ page }) => {
|
||||
|
||||
await test.step('Create a new test definition', async () => {
|
||||
// Navigate to Rules Library
|
||||
await page.goto('/rules-library');
|
||||
|
||||
// Click add button
|
||||
await page.getByTestId('add-test-definition-button').click();
|
||||
|
||||
// Wait for drawer to open
|
||||
await page.waitForSelector('.ant-drawer', { state: 'visible' });
|
||||
|
||||
// Verify drawer title
|
||||
await expect(page.locator('.ant-drawer-title')).toContainText(
|
||||
'Add Test Definition'
|
||||
);
|
||||
|
||||
// Fill in form fields
|
||||
await page.locator('#name').fill(TEST_DEFINITION_NAME);
|
||||
await page.locator('#displayName').fill(TEST_DEFINITION_DISPLAY_NAME);
|
||||
await page.locator('#description').fill(TEST_DEFINITION_DESCRIPTION);
|
||||
|
||||
// Select entity type
|
||||
await page.locator('#entityType').click();
|
||||
await page
|
||||
.locator('.ant-select-item-option-content:has-text("TABLE")')
|
||||
.first()
|
||||
.click();
|
||||
|
||||
// Select test platform
|
||||
await page.locator('#testPlatforms').click();
|
||||
await page
|
||||
.locator('.ant-select-item-option-content:has-text("dbt")')
|
||||
.first()
|
||||
.click();
|
||||
|
||||
// Wait for POST response when creating test definition
|
||||
const testDefinitionResponse = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'POST'
|
||||
);
|
||||
|
||||
// Click save
|
||||
await page.getByTestId('save-test-definition').click();
|
||||
|
||||
// Wait for API response
|
||||
const responseData = await testDefinitionResponse;
|
||||
|
||||
expect(responseData.status()).toBe(201);
|
||||
|
||||
// Wait for success toast
|
||||
await expect(page.getByText(/created successfully/i)).toBeVisible();
|
||||
|
||||
// Verify test definition appears in table
|
||||
await expect(page.getByTestId(TEST_DEFINITION_NAME)).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('Edit Test Definition', async () => {
|
||||
|
||||
// Wait for table to load
|
||||
await page.waitForSelector('[data-testid="test-definition-table"]', {
|
||||
state: 'visible',
|
||||
});
|
||||
|
||||
// Find and click edit button on first row
|
||||
const firstEditButton = page.getByTestId(`edit-test-definition-${TEST_DEFINITION_NAME}`).first();
|
||||
await firstEditButton.click();
|
||||
|
||||
// Wait for drawer to open
|
||||
await page.waitForSelector('.ant-drawer', { state: 'visible' });
|
||||
|
||||
// Verify drawer title
|
||||
await expect(page.locator('.ant-drawer-title')).toContainText(
|
||||
'Edit Test Definition'
|
||||
);
|
||||
|
||||
// Verify name field is disabled in edit mode
|
||||
const nameInput = page.locator('#name');
|
||||
|
||||
await expect(nameInput).toBeDisabled();
|
||||
|
||||
// Update display name
|
||||
const displayNameInput = page.getByLabel('Display Name');
|
||||
await displayNameInput.clear();
|
||||
await displayNameInput.fill(UPDATE_TEST_DEFINITION_DISPLAY_NAME);
|
||||
|
||||
// Wait for POST response when creating test definition
|
||||
const testDefinitionResponse = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'PATCH'
|
||||
);
|
||||
|
||||
// Click save
|
||||
await page.getByTestId('save-test-definition').click();
|
||||
// Wait for API response
|
||||
const responseData = await testDefinitionResponse;
|
||||
|
||||
expect(responseData.status()).toBe(200);
|
||||
|
||||
// Wait for success toast
|
||||
await expect(page.getByText(/updated successfully/i)).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('should enable/disable test definition', async () => {
|
||||
|
||||
// Wait for table to load
|
||||
await page.waitForSelector('[data-testid="test-definition-table"]', {
|
||||
state: 'visible',
|
||||
});
|
||||
|
||||
// Find first enabled switch
|
||||
const firstSwitch = page.getByTestId(`enable-switch-${TEST_DEFINITION_NAME}`)
|
||||
|
||||
// Wait for API call
|
||||
const testDefinitionResponse = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'PATCH'
|
||||
);
|
||||
// Toggle the switch
|
||||
await firstSwitch.click();
|
||||
|
||||
// Wait for API response
|
||||
const responseData = await testDefinitionResponse;
|
||||
|
||||
expect(responseData.status()).toBe(200);
|
||||
|
||||
// Wait for success toast
|
||||
await expect(page.getByText(/updated successfully/i)).toBeVisible();
|
||||
|
||||
// Verify switch state changed
|
||||
await expect(firstSwitch).toHaveAttribute(
|
||||
'aria-checked',
|
||||
String("false")
|
||||
);
|
||||
});
|
||||
|
||||
await test.step('should delete a test definition', async () => {
|
||||
|
||||
// Wait for table to load
|
||||
await page.waitForSelector('[data-testid="test-definition-table"]', {
|
||||
state: 'visible',
|
||||
});
|
||||
|
||||
// Find and click delete button
|
||||
const deleteButton = page.getByTestId(`delete-test-definition-${TEST_DEFINITION_NAME}`);
|
||||
await deleteButton.click();
|
||||
|
||||
// Wait for confirmation modal
|
||||
await page.waitForSelector('.ant-modal', { state: 'visible' });
|
||||
|
||||
// Verify modal content
|
||||
await expect(page.getByText(`Delete ${UPDATE_TEST_DEFINITION_DISPLAY_NAME}`)).toBeVisible();
|
||||
|
||||
await page.getByTestId("confirmation-text-input").fill("DELETE");
|
||||
|
||||
// Wait for API call
|
||||
const deleteTestDefinitionResponse = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'DELETE'
|
||||
);
|
||||
|
||||
// Click confirm delete
|
||||
await page.getByTestId("confirm-button").click();
|
||||
|
||||
const response = await deleteTestDefinitionResponse;
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
// Wait for success toast
|
||||
await expect(page.getByText(/deleted successfully/i)).toBeVisible();
|
||||
|
||||
// Verify test definition is removed from table
|
||||
await expect(page.getByText(TEST_DEFINITION_NAME)).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
test('should validate required fields in create form', async ({ page }) => {
|
||||
// Navigate to Rules Library
|
||||
await page.goto('/rules-library');
|
||||
|
||||
// Click add button
|
||||
await page.getByTestId('add-test-definition-button').click();
|
||||
|
||||
// Wait for drawer to open
|
||||
await page.waitForSelector('.ant-drawer', { state: 'visible' });
|
||||
|
||||
// Click save without filling required fields
|
||||
await page.getByTestId('save-test-definition').click();
|
||||
|
||||
// Verify validation errors appear for required fields
|
||||
await expect(
|
||||
page.locator('.ant-form-item-explain-error').first()
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('should cancel form and close drawer', async ({ page }) => {
|
||||
// Navigate to Rules Library
|
||||
await page.goto('/rules-library');
|
||||
|
||||
// Click add button
|
||||
await page.getByTestId('add-test-definition-button').click();
|
||||
|
||||
// Wait for drawer to open
|
||||
await page.waitForSelector('.ant-drawer', { state: 'visible' });
|
||||
|
||||
// Fill in some fields
|
||||
await page.locator('#name').fill('testName');
|
||||
|
||||
// Click cancel
|
||||
await page.getByRole('button', { name: /Cancel/i }).click();
|
||||
|
||||
// Verify drawer is closed
|
||||
await expect(page.locator('.ant-drawer')).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('should display pagination when test definitions exceed page size', async ({
|
||||
page,
|
||||
}) => {
|
||||
// Wait for API response promise before navigation
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'GET'
|
||||
);
|
||||
|
||||
await page.goto('/rules-library');
|
||||
const response = await responsePromise;
|
||||
const data = await response.json();
|
||||
|
||||
// Check if pagination component exists (NextPrevious component)
|
||||
const hasMultiplePages = data.paging && data.paging.total > 15;
|
||||
|
||||
if (!hasMultiplePages) {
|
||||
// Skip test if there aren't enough test definitions for pagination
|
||||
return;
|
||||
}
|
||||
|
||||
// Pagination uses NextPrevious component, not ant-pagination
|
||||
await expect(
|
||||
page
|
||||
.getByTestId('next')
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page
|
||||
.getByTestId('previous')
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('should search and filter test definitions', async ({ page }) => {
|
||||
// Navigate to Rules Library
|
||||
await page.goto('/rules-library');
|
||||
|
||||
// Wait for table to load
|
||||
await page.waitForSelector('[data-testid="test-definition-table"]', {
|
||||
state: 'visible',
|
||||
});
|
||||
|
||||
// Get initial row count
|
||||
const initialRows = await page
|
||||
.locator('[data-testid="test-definition-table"] tbody tr')
|
||||
.count();
|
||||
|
||||
// Use table search/filter if available
|
||||
const searchInput = page.getByPlaceholder(/Search/i);
|
||||
if (await searchInput.isVisible()) {
|
||||
await searchInput.fill('column');
|
||||
|
||||
// Wait for filtered results
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Verify filtered results
|
||||
const filteredRows = await page
|
||||
.locator('[data-testid="test-definition-table"] tbody tr')
|
||||
.count();
|
||||
|
||||
// Filtered results should be less than or equal to initial results
|
||||
expect(filteredRows).toBeLessThanOrEqual(initialRows);
|
||||
}
|
||||
});
|
||||
|
||||
test('should display test platform badges correctly', async ({ page }) => {
|
||||
// Navigate to Rules Library
|
||||
await page.goto('/rules-library');
|
||||
|
||||
// Wait for table to load
|
||||
await page.waitForSelector('[data-testid="test-definition-table"]', {
|
||||
state: 'visible',
|
||||
});
|
||||
|
||||
// Verify test platform tags/badges are displayed
|
||||
const platformTags = page.locator('.ant-tag, .ant-badge');
|
||||
const tagCount = await platformTags.count();
|
||||
|
||||
expect(tagCount).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('should not show edit and delete buttons for system test definitions', async ({
|
||||
page,
|
||||
}) => {
|
||||
// Wait for API response before navigation
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'GET'
|
||||
);
|
||||
|
||||
await page.goto('/rules-library');
|
||||
const response = await responsePromise;
|
||||
const data = await response.json();
|
||||
|
||||
// Find a system test definition (e.g., columnValueLengthsToBeBetween)
|
||||
const systemTestDef = data.data.find(
|
||||
(def: { provider: string; name: string }) =>
|
||||
def.provider === 'system'
|
||||
);
|
||||
|
||||
// Verify edit button does not exist for system test definition
|
||||
const editButton = page.getByTestId(
|
||||
`edit-test-definition-${systemTestDef.name}`
|
||||
);
|
||||
|
||||
await expect(editButton).toBeDisabled();
|
||||
|
||||
// Verify delete button does not exist for system test definition
|
||||
const deleteButton = page.getByTestId(
|
||||
`delete-test-definition-${systemTestDef.name}`
|
||||
);
|
||||
|
||||
await expect(deleteButton).toBeDisabled();
|
||||
|
||||
// Verify enabled switch still exists and is functional
|
||||
const row = page.locator(`[data-row-key="${systemTestDef.id}"]`);
|
||||
const enabledSwitch = row.getByRole('switch');
|
||||
|
||||
await expect(enabledSwitch).toBeVisible();
|
||||
|
||||
});
|
||||
|
||||
test('should allow enabling/disabling system test definitions', async ({
|
||||
page,
|
||||
}) => {
|
||||
// Wait for API response before navigation
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'GET'
|
||||
);
|
||||
|
||||
await page.goto('/rules-library');
|
||||
const response = await responsePromise;
|
||||
const data = await response.json();
|
||||
|
||||
// Wait for table to load
|
||||
await page.waitForSelector('[data-testid="test-definition-table"]', {
|
||||
state: 'visible',
|
||||
});
|
||||
|
||||
// Find a system test definition
|
||||
const systemTestDef = data.data.findLast(
|
||||
(def: { provider: string }) => def.provider === 'system'
|
||||
);
|
||||
|
||||
|
||||
const enabledSwitch = page.getByTestId(`enable-switch-${systemTestDef.name}`);
|
||||
|
||||
// Wait for API call and verify success
|
||||
const patchResponse = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'PATCH'
|
||||
);
|
||||
// Toggle the switch
|
||||
await enabledSwitch.click();
|
||||
|
||||
const disableResponse = await patchResponse;
|
||||
|
||||
expect(disableResponse.status()).toBe(200);
|
||||
|
||||
// Verify switch state changed
|
||||
await expect(enabledSwitch).toHaveAttribute(
|
||||
'aria-checked',
|
||||
String("false")
|
||||
);
|
||||
|
||||
const patchResponse2 = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'PATCH'
|
||||
);
|
||||
|
||||
// Toggle back to original state
|
||||
await enabledSwitch.click();
|
||||
const enableResponse = await patchResponse2;
|
||||
|
||||
expect(enableResponse.status()).toBe(200);
|
||||
|
||||
});
|
||||
|
||||
test('should display correct provider type for test definitions', async ({
|
||||
page,
|
||||
}) => {
|
||||
// Wait for API response before navigation
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions') &&
|
||||
response.request().method() === 'GET'
|
||||
);
|
||||
|
||||
await page.goto('/rules-library');
|
||||
const response = await responsePromise;
|
||||
const data = await response.json();
|
||||
|
||||
// Verify we have both system and user test definitions (if user ones exist)
|
||||
const systemDefs = data.data.filter(
|
||||
(def: { provider: string }) => def.provider === 'system'
|
||||
);
|
||||
const userDefs = data.data.filter(
|
||||
(def: { provider: string }) => def.provider === 'user'
|
||||
);
|
||||
|
||||
// Should have system test definitions
|
||||
expect(systemDefs.length).toBeGreaterThan(0);
|
||||
|
||||
// Verify system definitions have provider = 'system'
|
||||
systemDefs.forEach((def: { provider: string }) => {
|
||||
expect(def.provider).toBe('system');
|
||||
});
|
||||
|
||||
// If user definitions exist, verify they have provider = 'user'
|
||||
if (userDefs.length > 0) {
|
||||
userDefs.forEach((def: { provider: string }) => {
|
||||
expect(def.provider).toBe('user');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
* Copyright 2024 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 { test as base, expect, Page } from '@playwright/test';
|
||||
import { PolicyClass } from '../../../support/access-control/PoliciesClass';
|
||||
import { RolesClass } from '../../../support/access-control/RolesClass';
|
||||
import { UserClass } from '../../../support/user/UserClass';
|
||||
import { performAdminLogin } from '../../../utils/admin';
|
||||
import { getApiContext, redirectToHomePage, uuid } from '../../../utils/common';
|
||||
|
||||
|
||||
const actionNotAllowed = async (page: Page) => {
|
||||
// Verify "Add Test Definition" button is NOT visible (no Create permission)
|
||||
const addButton = page.getByTestId('add-test-definition-button');
|
||||
|
||||
await expect(addButton).not.toBeVisible();
|
||||
|
||||
// Verify edit buttons are NOT visible for user test definitions
|
||||
const editButtons = page.getByTestId(/edit-test-definition-/).first();
|
||||
await expect(editButtons).toBeDisabled();
|
||||
|
||||
// Verify delete buttons are NOT visible
|
||||
const deleteButtons = page.getByTestId(/delete-test-definition-/).first();
|
||||
await expect(deleteButtons).toBeDisabled();
|
||||
|
||||
// Verify enabled/disabled switches are NOT interactive (no EditAll permission)
|
||||
const firstSwitch = page.getByRole('switch').first();
|
||||
await expect(firstSwitch).toBeDisabled();
|
||||
}
|
||||
|
||||
// Define permission policies for different roles
|
||||
const TEST_DEFINITION_VIEW_ONLY_RULES = [
|
||||
{
|
||||
name: `test-definition-view-only-${uuid()}`,
|
||||
resources: ['testDefinition'],
|
||||
operations: ['ViewAll', 'ViewBasic'],
|
||||
effect: 'allow',
|
||||
},
|
||||
];
|
||||
|
||||
const TEST_DEFINITION_DATA_CONSUMER_RULES = [
|
||||
{
|
||||
name: `test-definition-data-consumer-${uuid()}`,
|
||||
resources: ['testDefinition'],
|
||||
operations: ['ViewAll', 'ViewBasic'],
|
||||
effect: 'allow',
|
||||
},
|
||||
];
|
||||
|
||||
const TEST_DEFINITION_DATA_STEWARD_RULES = [
|
||||
{
|
||||
name: `test-definition-data-steward-${uuid()}`,
|
||||
resources: ['testDefinition'],
|
||||
operations: ['ViewAll', 'ViewBasic', 'EditAll'],
|
||||
effect: 'allow',
|
||||
},
|
||||
];
|
||||
|
||||
// Create policy and role instances
|
||||
const dataConsumerPolicy = new PolicyClass();
|
||||
const dataConsumerRole = new RolesClass();
|
||||
const dataConsumerUser = new UserClass();
|
||||
|
||||
const dataStewardPolicy = new PolicyClass();
|
||||
const dataStewardRole = new RolesClass();
|
||||
const dataStewardUser = new UserClass();
|
||||
|
||||
const viewOnlyPolicy = new PolicyClass();
|
||||
const viewOnlyRole = new RolesClass();
|
||||
const viewOnlyUser = new UserClass();
|
||||
|
||||
const test = base.extend<{
|
||||
adminPage: Page;
|
||||
dataConsumerPage: Page;
|
||||
dataStewardPage: Page;
|
||||
viewOnlyPage: Page;
|
||||
}>({
|
||||
adminPage: async ({ browser }, use) => {
|
||||
const { page } = await performAdminLogin(browser);
|
||||
await use(page);
|
||||
await page.close();
|
||||
},
|
||||
dataConsumerPage: async ({ browser }, use) => {
|
||||
const page = await browser.newPage();
|
||||
await dataConsumerUser.login(page);
|
||||
await use(page);
|
||||
await page.close();
|
||||
},
|
||||
dataStewardPage: async ({ browser }, use) => {
|
||||
const page = await browser.newPage();
|
||||
await dataStewardUser.login(page);
|
||||
await use(page);
|
||||
await page.close();
|
||||
},
|
||||
viewOnlyPage: async ({ browser }, use) => {
|
||||
const page = await browser.newPage();
|
||||
await viewOnlyUser.login(page);
|
||||
await use(page);
|
||||
await page.close();
|
||||
},
|
||||
});
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
const { apiContext, afterAction } = await performAdminLogin(browser);
|
||||
|
||||
// Create view-only user with policy and role
|
||||
await viewOnlyUser.create(apiContext, false);
|
||||
const viewOnlyPolicyResponse = await viewOnlyPolicy.create(
|
||||
apiContext,
|
||||
TEST_DEFINITION_VIEW_ONLY_RULES
|
||||
);
|
||||
const viewOnlyRoleResponse = await viewOnlyRole.create(apiContext, [
|
||||
viewOnlyPolicyResponse.fullyQualifiedName,
|
||||
]);
|
||||
await viewOnlyUser.patch({
|
||||
apiContext,
|
||||
patchData: [
|
||||
{
|
||||
op: 'add',
|
||||
path: '/roles/0',
|
||||
value: {
|
||||
id: viewOnlyRoleResponse.id,
|
||||
type: 'role',
|
||||
name: viewOnlyRoleResponse.name,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Create data consumer user with policy and role
|
||||
await dataConsumerUser.create(apiContext, false);
|
||||
const dataConsumerPolicyResponse = await dataConsumerPolicy.create(
|
||||
apiContext,
|
||||
TEST_DEFINITION_DATA_CONSUMER_RULES
|
||||
);
|
||||
const dataConsumerRoleResponse = await dataConsumerRole.create(apiContext, [
|
||||
dataConsumerPolicyResponse.fullyQualifiedName,
|
||||
]);
|
||||
await dataConsumerUser.patch({
|
||||
apiContext,
|
||||
patchData: [
|
||||
{
|
||||
op: 'add',
|
||||
path: '/roles/0',
|
||||
value: {
|
||||
id: dataConsumerRoleResponse.id,
|
||||
type: 'role',
|
||||
name: dataConsumerRoleResponse.name,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Create data steward user with policy and role
|
||||
await dataStewardUser.create(apiContext, false);
|
||||
const dataStewardPolicyResponse = await dataStewardPolicy.create(
|
||||
apiContext,
|
||||
TEST_DEFINITION_DATA_STEWARD_RULES
|
||||
);
|
||||
const dataStewardRoleResponse = await dataStewardRole.create(apiContext, [
|
||||
dataStewardPolicyResponse.fullyQualifiedName,
|
||||
]);
|
||||
await dataStewardUser.patch({
|
||||
apiContext,
|
||||
patchData: [
|
||||
{
|
||||
op: 'add',
|
||||
path: '/roles/0',
|
||||
value: {
|
||||
id: dataStewardRoleResponse.id,
|
||||
type: 'role',
|
||||
name: dataStewardRoleResponse.name,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await afterAction();
|
||||
});
|
||||
|
||||
test.afterAll(async ({ browser }) => {
|
||||
const { apiContext, afterAction } = await performAdminLogin(browser);
|
||||
|
||||
// Cleanup users, roles, and policies
|
||||
await viewOnlyUser.delete(apiContext);
|
||||
await viewOnlyRole.delete(apiContext);
|
||||
await viewOnlyPolicy.delete(apiContext);
|
||||
|
||||
await dataConsumerUser.delete(apiContext);
|
||||
await dataConsumerRole.delete(apiContext);
|
||||
await dataConsumerPolicy.delete(apiContext);
|
||||
|
||||
await dataStewardUser.delete(apiContext);
|
||||
await dataStewardRole.delete(apiContext);
|
||||
await dataStewardPolicy.delete(apiContext);
|
||||
|
||||
await afterAction();
|
||||
});
|
||||
|
||||
test.describe('Test Definition Permissions - View Only User', () => {
|
||||
test('should allow viewing test definitions but not create, edit, or delete', async ({
|
||||
viewOnlyPage,
|
||||
}) => {
|
||||
await redirectToHomePage(viewOnlyPage);
|
||||
|
||||
// Navigate to Rules Library
|
||||
await viewOnlyPage.goto('/rules-library');
|
||||
|
||||
// Wait for table to load
|
||||
await viewOnlyPage.waitForSelector(
|
||||
'[data-testid="test-definition-table"]',
|
||||
{
|
||||
state: 'visible',
|
||||
}
|
||||
);
|
||||
|
||||
// Verify user can view the table
|
||||
await expect(
|
||||
viewOnlyPage.getByTestId('test-definition-table')
|
||||
).toBeVisible();
|
||||
|
||||
await actionNotAllowed(viewOnlyPage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Test Definition Permissions - Data Consumer', () => {
|
||||
test('should allow viewing test definitions but not create, edit, or delete', async ({
|
||||
dataConsumerPage,
|
||||
}) => {
|
||||
await redirectToHomePage(dataConsumerPage);
|
||||
|
||||
// Navigate to Rules Library
|
||||
await dataConsumerPage.goto('/rules-library');
|
||||
|
||||
// Wait for table to load
|
||||
await dataConsumerPage.waitForSelector(
|
||||
'[data-testid="test-definition-table"]',
|
||||
{
|
||||
state: 'visible',
|
||||
}
|
||||
);
|
||||
|
||||
// Verify user can view the table
|
||||
await expect(
|
||||
dataConsumerPage.getByTestId('test-definition-table')
|
||||
).toBeVisible();
|
||||
|
||||
await actionNotAllowed(dataConsumerPage);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Test Definition Permissions - Data Steward', () => {
|
||||
test('should allow viewing and editing but not creating or deleting test definitions', async ({
|
||||
dataStewardPage,
|
||||
}) => {
|
||||
await redirectToHomePage(dataStewardPage);
|
||||
|
||||
// Navigate to Rules Library
|
||||
await dataStewardPage.goto('/rules-library');
|
||||
|
||||
// Wait for table to load
|
||||
await dataStewardPage.waitForSelector(
|
||||
'[data-testid="test-definition-table"]',
|
||||
{
|
||||
state: 'visible',
|
||||
}
|
||||
);
|
||||
|
||||
// Verify user can view the table
|
||||
await expect(
|
||||
dataStewardPage.getByTestId('test-definition-table')
|
||||
).toBeVisible();
|
||||
|
||||
// Data Steward should NOT have Create permission
|
||||
const addButton = dataStewardPage.getByTestId('add-test-definition-button');
|
||||
|
||||
await expect(addButton).not.toBeVisible();
|
||||
|
||||
// Data Steward should be able to toggle enabled/disabled switches (EditAll permission)
|
||||
const firstSwitch = dataStewardPage.getByRole('switch').first();
|
||||
|
||||
await expect(firstSwitch).toBeEnabled();
|
||||
|
||||
// Wait for API call
|
||||
const response = dataStewardPage.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions/') &&
|
||||
response.request().method() === 'PATCH'
|
||||
);
|
||||
|
||||
// Try to toggle the switch
|
||||
await firstSwitch.click();
|
||||
await response;
|
||||
|
||||
// Verify switch state changed
|
||||
await expect(firstSwitch).toHaveAttribute(
|
||||
'aria-checked',
|
||||
String("false")
|
||||
);
|
||||
|
||||
const response2 = dataStewardPage.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions/') &&
|
||||
response.request().method() === 'PATCH'
|
||||
);
|
||||
// Toggle back to original state
|
||||
await firstSwitch.click();
|
||||
await response2;
|
||||
|
||||
await expect(firstSwitch).toHaveAttribute('aria-checked', String("true"));
|
||||
|
||||
|
||||
// Data Steward should NOT see delete buttons (no Delete permission)
|
||||
const deleteButtons = dataStewardPage.getByTestId(
|
||||
/delete-test-definition-/
|
||||
);
|
||||
await expect(deleteButtons.first()).toBeDisabled();
|
||||
});
|
||||
|
||||
test('should not be able to edit system test definitions', async ({
|
||||
dataStewardPage,
|
||||
}) => {
|
||||
await redirectToHomePage(dataStewardPage);
|
||||
// Wait for API response to get test definitions
|
||||
const response = dataStewardPage.waitForResponse((response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions')
|
||||
);
|
||||
|
||||
// Navigate to Rules Library
|
||||
await dataStewardPage.goto('/rules-library');
|
||||
|
||||
const responseResolved = await response;
|
||||
const data = await responseResolved.json();
|
||||
|
||||
// Find a system test definition
|
||||
const systemTestDef = data.data.find(
|
||||
(def: { provider: string }) => def.provider === 'system'
|
||||
);
|
||||
|
||||
|
||||
// Verify edit button does not exist for system test definition
|
||||
const editButton = dataStewardPage.getByTestId(
|
||||
`edit-test-definition-${systemTestDef.name}`
|
||||
);
|
||||
|
||||
await expect(editButton).toBeDisabled();
|
||||
|
||||
// Verify enabled switch exists and can be toggled
|
||||
const row = dataStewardPage.locator(
|
||||
`[data-row-key="${systemTestDef.id}"]`
|
||||
);
|
||||
const enabledSwitch = row.getByRole('switch');
|
||||
|
||||
await expect(enabledSwitch).toBeVisible();
|
||||
await expect(enabledSwitch).toBeEnabled();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Test Definition Permissions - API Level Validation', () => {
|
||||
test('should prevent unauthorized users from creating test definitions via API', async ({
|
||||
dataConsumerPage,
|
||||
}) => {
|
||||
await redirectToHomePage(dataConsumerPage);
|
||||
const { apiContext } = await getApiContext(dataConsumerPage);
|
||||
|
||||
// Try to create a test definition via API (should fail)
|
||||
const createResponse = await apiContext.post(
|
||||
'/api/v1/dataQuality/testDefinitions',
|
||||
{
|
||||
data: {
|
||||
name: 'unauthorizedTest',
|
||||
description: 'Should not be created',
|
||||
entityType: 'COLUMN',
|
||||
testPlatforms: ['OpenMetadata'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Verify the request failed with 403 Forbidden
|
||||
expect(createResponse.status()).toBe(403);
|
||||
});
|
||||
|
||||
test('should prevent unauthorized users from deleting test definitions via API', async ({
|
||||
dataStewardPage,
|
||||
adminPage
|
||||
}) => {
|
||||
await redirectToHomePage(dataStewardPage);
|
||||
await redirectToHomePage(adminPage);
|
||||
const { apiContext } = await getApiContext(dataStewardPage);
|
||||
const { apiContext: adminApiContext } = await getApiContext(adminPage);
|
||||
|
||||
const createResponse = await adminApiContext.post(
|
||||
'/api/v1/dataQuality/testDefinitions',
|
||||
{
|
||||
data: {
|
||||
name: `unauthorizedTest${uuid()}`,
|
||||
description: `unauthorizedTest`,
|
||||
entityType: 'COLUMN',
|
||||
testPlatforms: ['OpenMetadata'],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = await createResponse.json();
|
||||
|
||||
// Try to delete the test definition (should fail - no Delete permission)
|
||||
const deleteResponse = await apiContext.delete(
|
||||
`/api/v1/dataQuality/testDefinitions/${data.id}`
|
||||
);
|
||||
|
||||
// Verify the request failed with 403 Forbidden
|
||||
expect(deleteResponse.status()).toBe(403);
|
||||
|
||||
});
|
||||
|
||||
test('should prevent all users from modifying system test definition entity type via API', async ({
|
||||
adminPage,
|
||||
}) => {
|
||||
await redirectToHomePage(adminPage);
|
||||
const { apiContext } = await getApiContext(adminPage);
|
||||
|
||||
const response = adminPage.waitForResponse((response) =>
|
||||
response.url().includes('/api/v1/dataQuality/testDefinitions')
|
||||
);
|
||||
|
||||
// Navigate to Rules Library
|
||||
await adminPage.goto('/rules-library');
|
||||
|
||||
const responseResolved = await response;
|
||||
const data = await responseResolved.json();
|
||||
|
||||
// Find a system test definition with COLUMN entity type
|
||||
const systemTestDef = data.data.find(
|
||||
(def: { provider: string; entityType: string }) =>
|
||||
def.provider === 'system' && def.entityType === 'COLUMN'
|
||||
);
|
||||
|
||||
|
||||
// Try to patch the test definition to change entity type (should fail even for admin)
|
||||
const patchResponse = await apiContext.patch(
|
||||
`/api/v1/dataQuality/testDefinitions/${systemTestDef.id}`,
|
||||
{
|
||||
data: [
|
||||
{
|
||||
op: 'replace',
|
||||
path: '/entityType',
|
||||
value: 'TABLE',
|
||||
},
|
||||
],
|
||||
headers: {
|
||||
'Content-Type': 'application/json-patch+json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Verify the request failed with 400 Bad Request
|
||||
expect(patchResponse.status()).toBe(400);
|
||||
|
||||
const errorBody = await patchResponse.json();
|
||||
|
||||
expect(errorBody.message).toContain(
|
||||
'System test definitions cannot have their entity type modified'
|
||||
);
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -242,6 +242,10 @@ const IncidentManagerPage = withSuspenseFallback(
|
|||
React.lazy(() => import('../../pages/IncidentManager/IncidentManagerPage'))
|
||||
);
|
||||
|
||||
const RulesLibraryPage = withSuspenseFallback(
|
||||
React.lazy(() => import('../../pages/RulesLibrary/RulesLibraryPage'))
|
||||
);
|
||||
|
||||
const IncidentManagerDetailPage = withSuspenseFallback(
|
||||
React.lazy(
|
||||
() =>
|
||||
|
|
@ -586,6 +590,18 @@ const AuthenticatedAppRouter: FunctionComponent = () => {
|
|||
}
|
||||
path={ROUTES.INCIDENT_MANAGER}
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<AdminProtectedRoute
|
||||
hasPermission={userPermissions.hasViewPermissions(
|
||||
ResourceEntity.TEST_DEFINITION,
|
||||
permissions
|
||||
)}>
|
||||
<RulesLibraryPage />
|
||||
</AdminProtectedRoute>
|
||||
}
|
||||
path={ROUTES.RULES_LIBRARY}
|
||||
/>
|
||||
|
||||
{[
|
||||
ROUTES.TEST_CASE_DETAILS,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
* Copyright 2024 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 {
|
||||
MinusCircleOutlined,
|
||||
PlusOutlined,
|
||||
QuestionCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Drawer,
|
||||
Form,
|
||||
Input,
|
||||
Select,
|
||||
Space,
|
||||
Switch,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ReactComponent as CloseIcon } from '../../../assets/svg/close.svg';
|
||||
import { CSMode } from '../../../enums/codemirror.enum';
|
||||
import { CreateTestDefinition } from '../../../generated/api/tests/createTestDefinition';
|
||||
import {
|
||||
DataQualityDimensions,
|
||||
DataType,
|
||||
EntityType,
|
||||
TestDataType,
|
||||
TestDefinition,
|
||||
TestPlatform,
|
||||
} from '../../../generated/tests/testDefinition';
|
||||
import {
|
||||
createTestDefinition,
|
||||
patchTestDefinition,
|
||||
} from '../../../rest/testAPI';
|
||||
import { createScrollToErrorHandler } from '../../../utils/formUtils';
|
||||
import { showSuccessToast } from '../../../utils/ToastUtils';
|
||||
import AlertBar from '../../AlertBar/AlertBar';
|
||||
import FormItemLabel from '../../common/Form/FormItemLabel';
|
||||
import CodeEditor from '../../Database/SchemaEditor/CodeEditor';
|
||||
|
||||
interface TestDefinitionFormProps {
|
||||
initialValues?: TestDefinition;
|
||||
onSuccess: () => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const TestDefinitionForm: React.FC<TestDefinitionFormProps> = ({
|
||||
initialValues,
|
||||
onSuccess,
|
||||
onCancel,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState<string>('');
|
||||
const isEditMode = Boolean(initialValues);
|
||||
const scrollToError = useMemo(() => createScrollToErrorHandler(), []);
|
||||
|
||||
const handleSubmit = async (values: TestDefinition) => {
|
||||
setIsSubmitting(true);
|
||||
setErrorMessage('');
|
||||
try {
|
||||
if (isEditMode && initialValues) {
|
||||
const updatedValues = {
|
||||
...initialValues,
|
||||
...values,
|
||||
};
|
||||
const patch = compare(initialValues, updatedValues);
|
||||
if (patch.length > 0) {
|
||||
await patchTestDefinition(initialValues?.id ?? '', patch);
|
||||
}
|
||||
showSuccessToast(
|
||||
t('server.entity-updated-success', {
|
||||
entity: t('label.test-definition'),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
const payload: CreateTestDefinition = {
|
||||
name: values.name,
|
||||
displayName: values.displayName,
|
||||
description: values.description,
|
||||
sqlExpression: values.sqlExpression,
|
||||
entityType: values.entityType ?? EntityType.Table,
|
||||
testPlatforms: values.testPlatforms,
|
||||
dataQualityDimension: values.dataQualityDimension,
|
||||
supportedDataTypes: values.supportedDataTypes,
|
||||
parameterDefinition: values.parameterDefinition,
|
||||
};
|
||||
await createTestDefinition(payload);
|
||||
showSuccessToast(
|
||||
t('server.entity-created-success', {
|
||||
entity: t('label.test-definition'),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
onSuccess();
|
||||
} catch (error) {
|
||||
const errorMsg =
|
||||
(error as AxiosError<{ message: string }>)?.response?.data?.message ||
|
||||
(isEditMode
|
||||
? t('server.update-entity-error', {
|
||||
entity: t('label.test-definition'),
|
||||
})
|
||||
: t('server.create-entity-error', {
|
||||
entity: t('label.test-definition'),
|
||||
}));
|
||||
setErrorMessage(errorMsg);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
destroyOnClose
|
||||
open
|
||||
className="custom-drawer-style"
|
||||
closable={false}
|
||||
extra={
|
||||
<Button
|
||||
className="drawer-close-icon flex-center"
|
||||
data-testid="close-drawer-button"
|
||||
icon={<CloseIcon />}
|
||||
type="link"
|
||||
onClick={onCancel}
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<Space className="w-full justify-end">
|
||||
<Button onClick={onCancel}>{t('label.cancel')}</Button>
|
||||
<Button
|
||||
data-testid="save-test-definition"
|
||||
htmlType="submit"
|
||||
loading={isSubmitting}
|
||||
type="primary"
|
||||
onClick={() => form.submit()}>
|
||||
{t('label.save')}
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
title={
|
||||
isEditMode
|
||||
? t('label.edit-entity', { entity: t('label.test-definition') })
|
||||
: t('label.add-entity', { entity: t('label.test-definition') })
|
||||
}
|
||||
width={720}
|
||||
onClose={onCancel}>
|
||||
{errorMessage && (
|
||||
<div className="m-b-md">
|
||||
<AlertBar
|
||||
defafultExpand
|
||||
className="test-definition-form-alert"
|
||||
message={errorMessage}
|
||||
type="error"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Form
|
||||
className="new-form-style"
|
||||
form={form}
|
||||
initialValues={{
|
||||
...initialValues,
|
||||
testPlatforms: initialValues?.testPlatforms || [
|
||||
TestPlatform.OpenMetadata,
|
||||
],
|
||||
}}
|
||||
layout="vertical"
|
||||
onFinish={handleSubmit}
|
||||
onFinishFailed={scrollToError}>
|
||||
<Form.Item
|
||||
label={t('label.name')}
|
||||
name="name"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('message.field-text-is-required', {
|
||||
fieldText: t('label.name'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<Input
|
||||
disabled={isEditMode}
|
||||
placeholder={t('label.enter-entity-name', {
|
||||
entity: t('label.test-definition'),
|
||||
})}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label={t('label.display-name')} name="displayName">
|
||||
<Input
|
||||
placeholder={t('label.enter-entity-name', {
|
||||
entity: t('label.display-name'),
|
||||
})}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('label.description')}
|
||||
name="description"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('message.field-text-is-required', {
|
||||
fieldText: t('label.description'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<Input.TextArea
|
||||
placeholder={t('label.enter-entity-description', {
|
||||
entity: t('label.test-definition'),
|
||||
})}
|
||||
rows={4}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="sqlExpression">
|
||||
<CodeEditor
|
||||
refreshEditor
|
||||
showCopyButton
|
||||
className="custom-query-editor query-editor-h-200"
|
||||
mode={{ name: CSMode.SQL }}
|
||||
title={
|
||||
<div className="ant-form-item-label">
|
||||
<label className="d-flex align-items-center">
|
||||
<Typography.Text className="form-label-title">
|
||||
{t('label.sql-query')}
|
||||
</Typography.Text>
|
||||
<Tooltip title={t('message.test-definition-sql-query-help')}>
|
||||
<QuestionCircleOutlined className="ant-form-item-tooltip" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('label.entity-type')}
|
||||
name="entityType"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('message.field-text-is-required', {
|
||||
fieldText: t('label.entity-type'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<Select
|
||||
disabled={isEditMode}
|
||||
id="entityType"
|
||||
options={Object.values(EntityType).map((type) => ({
|
||||
label: type,
|
||||
value: type,
|
||||
}))}
|
||||
placeholder={t('label.select-field', {
|
||||
field: t('label.entity-type'),
|
||||
})}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('label.test-platform-plural')}
|
||||
name="testPlatforms"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('message.field-text-is-required', {
|
||||
fieldText: t('label.test-platform-plural'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<Select
|
||||
id="testPlatforms"
|
||||
mode="multiple"
|
||||
options={Object.values(TestPlatform).map((platform) => ({
|
||||
label: platform,
|
||||
value: platform,
|
||||
}))}
|
||||
placeholder={t('label.select-field', {
|
||||
field: t('label.test-platform-plural'),
|
||||
})}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('label.data-quality-dimension')}
|
||||
name="dataQualityDimension">
|
||||
<Select
|
||||
options={Object.values(DataQualityDimensions).map((dimension) => ({
|
||||
label: dimension,
|
||||
value: dimension,
|
||||
}))}
|
||||
placeholder={t('label.select-field', {
|
||||
field: t('label.data-quality-dimension'),
|
||||
})}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('label.supported-data-type-plural')}
|
||||
name="supportedDataTypes">
|
||||
<Select
|
||||
mode="multiple"
|
||||
options={Object.values(DataType).map((dataType) => ({
|
||||
label: dataType,
|
||||
value: dataType,
|
||||
}))}
|
||||
placeholder={t('label.select-field', {
|
||||
field: t('label.supported-data-type-plural'),
|
||||
})}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={
|
||||
<FormItemLabel
|
||||
helperText={t('message.test-definition-parameters-description')}
|
||||
label={t('label.parameter-plural')}
|
||||
/>
|
||||
}>
|
||||
<Form.List name="parameterDefinition">
|
||||
{(fields, { add, remove }) => (
|
||||
<>
|
||||
{fields.map(({ key, name, ...restField }) => (
|
||||
<Card
|
||||
extra={<MinusCircleOutlined onClick={() => remove(name)} />}
|
||||
key={key}
|
||||
size="small"
|
||||
style={{ marginTop: 16 }}
|
||||
title={`${t('label.parameter')} ${name + 1}`}>
|
||||
<Form.Item
|
||||
{...restField}
|
||||
label={t('label.name')}
|
||||
name={[name, 'name']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('message.field-text-is-required', {
|
||||
fieldText: t('label.name'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<Input placeholder={t('label.parameter-name')} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
{...restField}
|
||||
label={t('label.display-name')}
|
||||
name={[name, 'displayName']}>
|
||||
<Input placeholder={t('label.parameter-display-name')} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
{...restField}
|
||||
label={t('label.description')}
|
||||
name={[name, 'description']}>
|
||||
<Input.TextArea
|
||||
placeholder={t('label.parameter-description')}
|
||||
rows={2}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
{...restField}
|
||||
label={t('label.data-type')}
|
||||
name={[name, 'dataType']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('message.field-text-is-required', {
|
||||
fieldText: t('label.data-type'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<Select
|
||||
options={Object.values(TestDataType).map((type) => ({
|
||||
label: type,
|
||||
value: type,
|
||||
}))}
|
||||
placeholder={t('label.select-field', {
|
||||
field: t('label.data-type'),
|
||||
})}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
{...restField}
|
||||
label={t('label.required')}
|
||||
name={[name, 'required']}
|
||||
valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Card>
|
||||
))}
|
||||
<Button
|
||||
block
|
||||
icon={<PlusOutlined />}
|
||||
style={{ marginTop: 16 }}
|
||||
type="dashed"
|
||||
onClick={() => add()}>
|
||||
{t('label.add-entity', { entity: t('label.parameter') })}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Form.List>
|
||||
</Form.Item>
|
||||
{isEditMode && (
|
||||
<Form.Item
|
||||
label={t('label.enabled')}
|
||||
name="enabled"
|
||||
style={{ marginTop: 16 }}
|
||||
valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestDefinitionForm;
|
||||
|
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Copyright 2024 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 {
|
||||
act,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
} from '@testing-library/react';
|
||||
import {
|
||||
DataQualityDimensions,
|
||||
DataType,
|
||||
EntityType,
|
||||
TestDefinition,
|
||||
TestPlatform,
|
||||
} from '../../../generated/tests/testDefinition';
|
||||
import {
|
||||
createTestDefinition,
|
||||
patchTestDefinition,
|
||||
} from '../../../rest/testAPI';
|
||||
import TestDefinitionForm from './TestDefinitionForm.component';
|
||||
|
||||
const mockOnSuccess = jest.fn();
|
||||
const mockOnCancel = jest.fn();
|
||||
|
||||
const mockInitialValues: TestDefinition = {
|
||||
id: 'test-def-1',
|
||||
name: 'columnValuesToBeNotNull',
|
||||
displayName: 'Column Values To Be Not Null',
|
||||
description: 'Ensures that all values in a column are not null',
|
||||
entityType: EntityType.Column,
|
||||
testPlatforms: [TestPlatform.OpenMetadata],
|
||||
dataQualityDimension: DataQualityDimensions.Completeness,
|
||||
supportedDataTypes: [DataType.String, DataType.Int],
|
||||
enabled: true,
|
||||
sqlExpression: 'SELECT * FROM {table} WHERE {column} IS NOT NULL',
|
||||
};
|
||||
|
||||
jest.mock('../../../rest/testAPI', () => ({
|
||||
createTestDefinition: jest.fn(),
|
||||
patchTestDefinition: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/ToastUtils', () => ({
|
||||
showSuccessToast: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../AlertBar/AlertBar', () => ({
|
||||
__esModule: true,
|
||||
default: jest
|
||||
.fn()
|
||||
.mockImplementation(({ message }) => (
|
||||
<div data-testid="alert-bar">{message}</div>
|
||||
)),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/formUtils', () => ({
|
||||
createScrollToErrorHandler: jest.fn(() => jest.fn()),
|
||||
}));
|
||||
|
||||
jest.mock('../../Database/SchemaEditor/CodeEditor', () => ({
|
||||
__esModule: true,
|
||||
default: jest
|
||||
.fn()
|
||||
.mockImplementation(({ value, onChange }) => (
|
||||
<textarea
|
||||
data-testid="code-editor"
|
||||
value={value}
|
||||
onChange={(e) => onChange?.(e.target.value)}
|
||||
/>
|
||||
)),
|
||||
}));
|
||||
|
||||
describe('TestDefinitionForm Component', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(createTestDefinition as jest.Mock).mockResolvedValue({});
|
||||
(patchTestDefinition as jest.Mock).mockResolvedValue({});
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render form in create mode with all required fields', () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
expect(screen.getByLabelText('label.name')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('label.display-name')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('label.description')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('code-editor')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('label.entity-type')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByLabelText('label.test-platform-plural')
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByLabelText('label.data-quality-dimension')
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByLabelText('label.supported-data-type-plural')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByTestId('save-test-definition')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render form in edit mode with initial values populated', () => {
|
||||
render(
|
||||
<TestDefinitionForm
|
||||
initialValues={mockInitialValues}
|
||||
onCancel={mockOnCancel}
|
||||
onSuccess={mockOnSuccess}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('label.edit-entity')).toBeInTheDocument();
|
||||
|
||||
const nameInput = screen.getByLabelText('label.name') as HTMLInputElement;
|
||||
|
||||
expect(nameInput.value).toBe('columnValuesToBeNotNull');
|
||||
expect(nameInput).toBeDisabled();
|
||||
|
||||
const displayNameInput = screen.getByLabelText(
|
||||
'label.display-name'
|
||||
) as HTMLInputElement;
|
||||
|
||||
expect(displayNameInput.value).toBe('Column Values To Be Not Null');
|
||||
|
||||
const descriptionInput = screen.getByLabelText(
|
||||
'label.description'
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
expect(descriptionInput.value).toBe(
|
||||
'Ensures that all values in a column are not null'
|
||||
);
|
||||
});
|
||||
|
||||
it('should render SQL query editor section', () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('code-editor')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render parameter section with add button', () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const addButtons = screen.getAllByRole('button', {
|
||||
name: /label.add-entity/i,
|
||||
});
|
||||
|
||||
expect(addButtons.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Form Field Behavior', () => {
|
||||
it('should disable name field in edit mode', () => {
|
||||
render(
|
||||
<TestDefinitionForm
|
||||
initialValues={mockInitialValues}
|
||||
onCancel={mockOnCancel}
|
||||
onSuccess={mockOnSuccess}
|
||||
/>
|
||||
);
|
||||
|
||||
const nameInput = screen.getByLabelText('label.name');
|
||||
|
||||
expect(nameInput).toBeDisabled();
|
||||
});
|
||||
|
||||
it('should enable name field in create mode', () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const nameInput = screen.getByLabelText('label.name');
|
||||
|
||||
expect(nameInput).not.toBeDisabled();
|
||||
});
|
||||
|
||||
it('should show enabled switch in edit mode', () => {
|
||||
render(
|
||||
<TestDefinitionForm
|
||||
initialValues={mockInitialValues}
|
||||
onCancel={mockOnCancel}
|
||||
onSuccess={mockOnSuccess}
|
||||
/>
|
||||
);
|
||||
|
||||
const enabledSwitch = screen.getByRole('switch');
|
||||
|
||||
expect(enabledSwitch).toBeInTheDocument();
|
||||
expect(enabledSwitch).toBeChecked();
|
||||
});
|
||||
|
||||
it('should not show enabled switch in create mode', () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const switches = screen.queryAllByRole('switch');
|
||||
|
||||
expect(switches).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should update SQL expression when typing in editor', async () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const sqlEditor = screen.getByTestId(
|
||||
'code-editor'
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.change(sqlEditor, {
|
||||
target: { value: 'SELECT * FROM {table} WHERE {column} IS NOT NULL' },
|
||||
});
|
||||
});
|
||||
|
||||
expect(sqlEditor.value).toBe(
|
||||
'SELECT * FROM {table} WHERE {column} IS NOT NULL'
|
||||
);
|
||||
});
|
||||
|
||||
it('should populate SQL expression in edit mode', () => {
|
||||
render(
|
||||
<TestDefinitionForm
|
||||
initialValues={mockInitialValues}
|
||||
onCancel={mockOnCancel}
|
||||
onSuccess={mockOnSuccess}
|
||||
/>
|
||||
);
|
||||
|
||||
const sqlEditor = screen.getByTestId('code-editor');
|
||||
|
||||
expect(sqlEditor).toHaveValue(
|
||||
'SELECT * FROM {table} WHERE {column} IS NOT NULL'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Parameter Management', () => {
|
||||
it('should add new parameter when add button is clicked', async () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const addButtons = screen.getAllByText('label.add-entity');
|
||||
const parameterAddButton = addButtons[addButtons.length - 1];
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(parameterAddButton);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('label.parameter 1')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByPlaceholderText('label.parameter-name')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove parameter when remove button is clicked', async () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const addButtons = screen.getAllByText('label.add-entity');
|
||||
const parameterAddButton = addButtons[addButtons.length - 1];
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(parameterAddButton);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('label.parameter 1')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const removeButton = screen.getByLabelText('minus-circle');
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(removeButton);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('label.parameter 1')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Form Validation', () => {
|
||||
it('should show validation errors when required fields are empty', async () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const saveButton = screen.getByTestId('save-test-definition');
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(saveButton);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const errors = screen.getAllByText('message.field-text-is-required');
|
||||
|
||||
expect(errors.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Form Submission', () => {
|
||||
it('should have save button that triggers form submission', () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const saveButton = screen.getByTestId('save-test-definition');
|
||||
|
||||
expect(saveButton).toBeInTheDocument();
|
||||
expect(saveButton).toHaveTextContent('label.save');
|
||||
});
|
||||
|
||||
it('should render form with proper structure for submission', () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
expect(screen.getByLabelText('label.name')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('label.description')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('label.entity-type')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByLabelText('label.test-platform-plural')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByTestId('save-test-definition')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should initialize with testPlatforms field in edit mode', () => {
|
||||
render(
|
||||
<TestDefinitionForm
|
||||
initialValues={mockInitialValues}
|
||||
onCancel={mockOnCancel}
|
||||
onSuccess={mockOnSuccess}
|
||||
/>
|
||||
);
|
||||
|
||||
const testPlatformField = screen.getByLabelText(
|
||||
'label.test-platform-plural'
|
||||
);
|
||||
|
||||
expect(testPlatformField).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('User Interactions', () => {
|
||||
it('should call onCancel when cancel button is clicked', () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const cancelButton = screen.getByText('label.cancel');
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(mockOnCancel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should close drawer when clicking close icon', () => {
|
||||
render(
|
||||
<TestDefinitionForm onCancel={mockOnCancel} onSuccess={mockOnSuccess} />
|
||||
);
|
||||
|
||||
const drawer = screen.getByRole('dialog');
|
||||
|
||||
expect(drawer).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* Copyright 2024 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 {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Row,
|
||||
Skeleton,
|
||||
Space,
|
||||
Switch,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import { AxiosError } from 'axios';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ReactComponent as IconEdit } from '../../../assets/svg/edit-new.svg';
|
||||
import { ReactComponent as IconDelete } from '../../../assets/svg/ic-delete.svg';
|
||||
import { usePermissionProvider } from '../../../context/PermissionProvider/PermissionProvider';
|
||||
import {
|
||||
OperationPermission,
|
||||
ResourceEntity,
|
||||
} from '../../../context/PermissionProvider/PermissionProvider.interface';
|
||||
import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum';
|
||||
import { ProviderType } from '../../../generated/entity/bot';
|
||||
import { Operation } from '../../../generated/entity/policies/policy';
|
||||
import { TestDefinition } from '../../../generated/tests/testDefinition';
|
||||
import { Paging } from '../../../generated/type/paging';
|
||||
import { usePaging } from '../../../hooks/paging/usePaging';
|
||||
import {
|
||||
deleteTestDefinitionByFqn,
|
||||
getListTestDefinitions,
|
||||
patchTestDefinition,
|
||||
} from '../../../rest/testAPI';
|
||||
import { getEntityName } from '../../../utils/EntityUtils';
|
||||
import {
|
||||
checkPermission,
|
||||
DEFAULT_ENTITY_PERMISSION,
|
||||
} from '../../../utils/PermissionsUtils';
|
||||
import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils';
|
||||
import ErrorPlaceHolder from '../../common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
||||
import Loader from '../../common/Loader/Loader';
|
||||
import { PagingHandlerParams } from '../../common/NextPrevious/NextPrevious.interface';
|
||||
import RichTextEditorPreviewerNew from '../../common/RichTextEditor/RichTextEditorPreviewNew';
|
||||
import Table from '../../common/Table/Table';
|
||||
import EntityDeleteModal from '../../Modals/EntityDeleteModal/EntityDeleteModal';
|
||||
import TestDefinitionForm from '../TestDefinitionForm/TestDefinitionForm.component';
|
||||
|
||||
const TestDefinitionList = () => {
|
||||
const { t } = useTranslation();
|
||||
const { permissions, getEntityPermissionByFqn } = usePermissionProvider();
|
||||
const {
|
||||
currentPage,
|
||||
paging,
|
||||
pageSize,
|
||||
handlePagingChange,
|
||||
handlePageChange,
|
||||
showPagination,
|
||||
pagingCursor,
|
||||
} = usePaging();
|
||||
|
||||
const [testDefinitions, setTestDefinitions] = useState<TestDefinition[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [selectedDefinition, setSelectedDefinition] = useState<
|
||||
TestDefinition | undefined
|
||||
>();
|
||||
const [isFormVisible, setIsFormVisible] = useState(false);
|
||||
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
|
||||
const [definitionToDelete, setDefinitionToDelete] = useState<
|
||||
TestDefinition | undefined
|
||||
>();
|
||||
const [testDefinitionPermissions, setTestDefinitionPermissions] = useState<
|
||||
Record<string, OperationPermission>
|
||||
>({});
|
||||
const [permissionLoading, setPermissionLoading] = useState(true);
|
||||
|
||||
const createPermission = useMemo(
|
||||
() =>
|
||||
checkPermission(
|
||||
Operation.Create,
|
||||
ResourceEntity.TEST_DEFINITION,
|
||||
permissions
|
||||
),
|
||||
[permissions]
|
||||
);
|
||||
|
||||
const viewPermission = useMemo(
|
||||
() =>
|
||||
checkPermission(
|
||||
Operation.ViewBasic,
|
||||
ResourceEntity.TEST_DEFINITION,
|
||||
permissions
|
||||
) ||
|
||||
checkPermission(
|
||||
Operation.ViewAll,
|
||||
ResourceEntity.TEST_DEFINITION,
|
||||
permissions
|
||||
),
|
||||
[permissions]
|
||||
);
|
||||
|
||||
const fetchTestDefinitionPermissions = useCallback(
|
||||
async (definitions: TestDefinition[]) => {
|
||||
try {
|
||||
setPermissionLoading(true);
|
||||
|
||||
if (!definitions.length) {
|
||||
setTestDefinitionPermissions({});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch permissions for all definitions (including system definitions)
|
||||
const permissionPromises: Promise<OperationPermission>[] =
|
||||
definitions.map((def) =>
|
||||
getEntityPermissionByFqn(
|
||||
ResourceEntity.TEST_DEFINITION,
|
||||
def.fullyQualifiedName ?? ''
|
||||
)
|
||||
);
|
||||
|
||||
const permissionResponses = await Promise.allSettled(
|
||||
permissionPromises
|
||||
);
|
||||
|
||||
const permissionsMap = definitions.reduce((acc, def, idx) => {
|
||||
const response = permissionResponses[idx];
|
||||
|
||||
return {
|
||||
...acc,
|
||||
[def.name]:
|
||||
response?.status === 'fulfilled'
|
||||
? response.value
|
||||
: DEFAULT_ENTITY_PERMISSION,
|
||||
};
|
||||
}, {} as Record<string, OperationPermission>);
|
||||
|
||||
setTestDefinitionPermissions(permissionsMap);
|
||||
} catch (error) {
|
||||
showErrorToast(error as AxiosError);
|
||||
} finally {
|
||||
setPermissionLoading(false);
|
||||
}
|
||||
},
|
||||
[getEntityPermissionByFqn]
|
||||
);
|
||||
|
||||
const fetchTestDefinitions = useCallback(
|
||||
async (pagingOffset?: Partial<Paging>) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const { data, paging: responsePaging } = await getListTestDefinitions({
|
||||
after: pagingOffset?.after,
|
||||
before: pagingOffset?.before,
|
||||
limit: pageSize,
|
||||
});
|
||||
setTestDefinitions(data);
|
||||
handlePagingChange(responsePaging);
|
||||
// Fetch permissions asynchronously to avoid blocking list render
|
||||
fetchTestDefinitionPermissions(data);
|
||||
} catch (error) {
|
||||
showErrorToast(error as AxiosError);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
},
|
||||
[pageSize, handlePagingChange, fetchTestDefinitionPermissions]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const { cursorType, cursorValue } = pagingCursor ?? {};
|
||||
|
||||
if (cursorType && cursorValue) {
|
||||
fetchTestDefinitions({ [cursorType]: cursorValue });
|
||||
} else {
|
||||
fetchTestDefinitions();
|
||||
}
|
||||
}, [pageSize, pagingCursor]);
|
||||
|
||||
const handleEnableToggle = async (
|
||||
record: TestDefinition,
|
||||
checked: boolean
|
||||
) => {
|
||||
try {
|
||||
const updatedData = { ...record, enabled: checked };
|
||||
const patch = compare(record, updatedData);
|
||||
|
||||
await patchTestDefinition(record.id ?? '', patch);
|
||||
showSuccessToast(
|
||||
t('server.entity-updated-success', {
|
||||
entity: t('label.test-definition'),
|
||||
})
|
||||
);
|
||||
// Optimistically update the local state instead of re-fetching
|
||||
setTestDefinitions((prev) =>
|
||||
prev.map((item) =>
|
||||
item.id === record.id
|
||||
? {
|
||||
...item,
|
||||
enabled: checked,
|
||||
}
|
||||
: item
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
showErrorToast(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEdit = (record: TestDefinition) => {
|
||||
setSelectedDefinition(record);
|
||||
setIsFormVisible(true);
|
||||
};
|
||||
|
||||
const handleDeleteClick = (record: TestDefinition) => {
|
||||
setDefinitionToDelete(record);
|
||||
setIsDeleteModalVisible(true);
|
||||
};
|
||||
|
||||
const handleDeleteConfirm = async () => {
|
||||
if (!definitionToDelete) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await deleteTestDefinitionByFqn(
|
||||
definitionToDelete.fullyQualifiedName ?? ''
|
||||
);
|
||||
showSuccessToast(
|
||||
t('server.entity-deleted-success', {
|
||||
entity: t('label.test-definition'),
|
||||
})
|
||||
);
|
||||
setIsDeleteModalVisible(false);
|
||||
setDefinitionToDelete(undefined);
|
||||
fetchTestDefinitions();
|
||||
} catch (error) {
|
||||
showErrorToast(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteCancel = () => {
|
||||
setIsDeleteModalVisible(false);
|
||||
setDefinitionToDelete(undefined);
|
||||
};
|
||||
|
||||
const handleFormSuccess = () => {
|
||||
setIsFormVisible(false);
|
||||
setSelectedDefinition(undefined);
|
||||
fetchTestDefinitions();
|
||||
};
|
||||
|
||||
const handleFormCancel = () => {
|
||||
setIsFormVisible(false);
|
||||
setSelectedDefinition(undefined);
|
||||
};
|
||||
|
||||
const columns: ColumnsType<TestDefinition> = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: t('label.name'),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 250,
|
||||
render: (name: string, record: TestDefinition) => (
|
||||
<Typography.Text data-testid={name}>
|
||||
{getEntityName(record)}
|
||||
</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('label.description'),
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
ellipsis: true,
|
||||
render: (description: string) => (
|
||||
<RichTextEditorPreviewerNew markdown={description} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('label.entity-type'),
|
||||
dataIndex: 'entityType',
|
||||
key: 'entityType',
|
||||
width: 150,
|
||||
render: (entityType: string) => (
|
||||
<Typography.Text>{entityType}</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('label.test-platform-plural'),
|
||||
dataIndex: 'testPlatforms',
|
||||
key: 'testPlatforms',
|
||||
width: 200,
|
||||
render: (testPlatforms: string[]) => (
|
||||
<Typography.Text>{testPlatforms?.join(', ') ?? '--'}</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('label.enabled'),
|
||||
dataIndex: 'enabled',
|
||||
key: 'enabled',
|
||||
width: 100,
|
||||
render: (enabled: boolean, record: TestDefinition) => {
|
||||
const entityPermissions = testDefinitionPermissions[record.name];
|
||||
const hasEditPermission = entityPermissions?.[Operation.EditAll];
|
||||
|
||||
if (permissionLoading || !entityPermissions) {
|
||||
return (
|
||||
<Skeleton.Button active size="small" style={{ width: 32 }} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
!hasEditPermission && t('message.no-permission-for-action')
|
||||
}>
|
||||
<Switch
|
||||
checked={enabled ?? true}
|
||||
data-testid={`enable-switch-${record.name}`}
|
||||
disabled={!hasEditPermission}
|
||||
size="small"
|
||||
onChange={(checked) => handleEnableToggle(record, checked)}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('label.action-plural'),
|
||||
key: 'actions',
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
render: (_, record: TestDefinition) => {
|
||||
const isSystemProvider = record.provider === ProviderType.System;
|
||||
const entityPermissions = testDefinitionPermissions[record.name];
|
||||
const hasEditPermission = entityPermissions?.[Operation.EditAll];
|
||||
const hasDeletePermission = entityPermissions?.[Operation.Delete];
|
||||
|
||||
if (permissionLoading || !entityPermissions) {
|
||||
return (
|
||||
<Skeleton.Button active size="small" style={{ width: 24 }} />
|
||||
);
|
||||
}
|
||||
|
||||
const editTooltip = isSystemProvider
|
||||
? t('message.system-test-definition-edit-warning')
|
||||
: !hasEditPermission
|
||||
? t('message.no-permission-for-action')
|
||||
: t('label.edit');
|
||||
|
||||
const deleteTooltip = isSystemProvider
|
||||
? t('message.system-test-definition-delete-warning')
|
||||
: !hasDeletePermission
|
||||
? t('message.no-permission-for-action')
|
||||
: t('label.delete');
|
||||
|
||||
return (
|
||||
<Space size={0}>
|
||||
<Tooltip title={editTooltip}>
|
||||
<Button
|
||||
data-testid={`edit-test-definition-${record.name}`}
|
||||
disabled={isSystemProvider || !hasEditPermission}
|
||||
icon={<IconEdit height={16} width={16} />}
|
||||
type="text"
|
||||
onClick={() => handleEdit(record)}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title={deleteTooltip}>
|
||||
<Button
|
||||
data-testid={`delete-test-definition-${record.name}`}
|
||||
disabled={isSystemProvider || !hasDeletePermission}
|
||||
icon={<IconDelete height={16} width={16} />}
|
||||
type="text"
|
||||
onClick={() => handleDeleteClick(record)}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
[t, testDefinitionPermissions]
|
||||
);
|
||||
|
||||
const handlePageChangeCallback = ({
|
||||
cursorType,
|
||||
currentPage,
|
||||
}: PagingHandlerParams) => {
|
||||
if (cursorType && paging) {
|
||||
fetchTestDefinitions({
|
||||
[cursorType]: paging[cursorType],
|
||||
total: paging.total,
|
||||
} as Paging);
|
||||
handlePageChange(
|
||||
currentPage,
|
||||
{ cursorType, cursorValue: paging[cursorType] },
|
||||
pageSize
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const customPaginationProps = useMemo(
|
||||
() => ({
|
||||
currentPage: currentPage,
|
||||
pageSize: pageSize,
|
||||
paging: paging,
|
||||
pagingHandler: handlePageChangeCallback,
|
||||
showPagination: showPagination,
|
||||
}),
|
||||
[
|
||||
currentPage,
|
||||
paging,
|
||||
pageSize,
|
||||
handlePagingChange,
|
||||
handlePageChange,
|
||||
showPagination,
|
||||
]
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
if (!viewPermission) {
|
||||
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Row className="p-b-md" gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<Row justify="space-between">
|
||||
<Col>
|
||||
<Typography.Title level={5}>
|
||||
{t('label.test-definition-plural')}
|
||||
</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
{t('message.page-sub-header-for-test-definitions')}
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
{createPermission && (
|
||||
<Col>
|
||||
<Button
|
||||
data-testid="add-test-definition-button"
|
||||
type="primary"
|
||||
onClick={() => setIsFormVisible(true)}>
|
||||
{t('label.add-entity', {
|
||||
entity: t('label.test-definition'),
|
||||
})}
|
||||
</Button>
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
{testDefinitions.length > 0 ? (
|
||||
<Table
|
||||
bordered
|
||||
columns={columns}
|
||||
customPaginationProps={customPaginationProps}
|
||||
data-testid="test-definition-table"
|
||||
dataSource={testDefinitions}
|
||||
loading={isLoading}
|
||||
pagination={false}
|
||||
rowKey="id"
|
||||
scroll={{ x: 1200 }}
|
||||
size="small"
|
||||
/>
|
||||
) : (
|
||||
<ErrorPlaceHolder />
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{isFormVisible && (
|
||||
<TestDefinitionForm
|
||||
initialValues={selectedDefinition}
|
||||
onCancel={handleFormCancel}
|
||||
onSuccess={handleFormSuccess}
|
||||
/>
|
||||
)}
|
||||
|
||||
<EntityDeleteModal
|
||||
entityName={getEntityName(definitionToDelete)}
|
||||
entityType={t('label.test-definition')}
|
||||
visible={isDeleteModalVisible}
|
||||
onCancel={handleDeleteCancel}
|
||||
onConfirm={handleDeleteConfirm}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestDefinitionList;
|
||||
|
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* Copyright 2024 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 { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { ResourceEntity } from '../../../context/PermissionProvider/PermissionProvider.interface';
|
||||
import { ProviderType } from '../../../generated/entity/bot';
|
||||
import {
|
||||
deleteTestDefinitionByFqn,
|
||||
getListTestDefinitions,
|
||||
patchTestDefinition,
|
||||
} from '../../../rest/testAPI';
|
||||
import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils';
|
||||
import TestDefinitionForm from '../TestDefinitionForm/TestDefinitionForm.component';
|
||||
import TestDefinitionList from './TestDefinitionList.component';
|
||||
|
||||
const mockTestDefinitions = {
|
||||
data: [
|
||||
{
|
||||
id: 'test-def-1',
|
||||
name: 'columnValuesToBeNotNull',
|
||||
fullyQualifiedName: 'columnValuesToBeNotNull',
|
||||
displayName: 'Column Values To Be Not Null',
|
||||
description: 'Ensures that all values in a column are not null',
|
||||
entityType: 'COLUMN',
|
||||
testPlatforms: ['OpenMetadata'],
|
||||
enabled: true,
|
||||
provider: ProviderType.User,
|
||||
},
|
||||
{
|
||||
id: 'test-def-2',
|
||||
name: 'tableRowCountToBeBetween',
|
||||
fullyQualifiedName: 'tableRowCountToBeBetween',
|
||||
displayName: 'Table Row Count To Be Between',
|
||||
description: 'Ensures table row count is between min and max values',
|
||||
entityType: 'TABLE',
|
||||
testPlatforms: ['OpenMetadata', 'DBT'],
|
||||
enabled: false,
|
||||
provider: ProviderType.System,
|
||||
},
|
||||
],
|
||||
paging: {
|
||||
total: 2,
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('../../../rest/testAPI', () => ({
|
||||
getListTestDefinitions: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve(mockTestDefinitions)),
|
||||
patchTestDefinition: jest.fn().mockImplementation(() => Promise.resolve({})),
|
||||
deleteTestDefinitionByFqn: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve({})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/ToastUtils', () => ({
|
||||
showSuccessToast: jest.fn(),
|
||||
showErrorToast: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../TestDefinitionForm/TestDefinitionForm.component', () => ({
|
||||
__esModule: true,
|
||||
default: jest
|
||||
.fn()
|
||||
.mockImplementation(() => (
|
||||
<div data-testid="test-definition-form">TestDefinitionForm</div>
|
||||
)),
|
||||
}));
|
||||
|
||||
jest.mock('../../../components/PageLayoutV1/PageLayoutV1', () => ({
|
||||
__esModule: true,
|
||||
default: jest
|
||||
.fn()
|
||||
.mockImplementation(({ children }) => (
|
||||
<div data-testid="page-layout">{children}</div>
|
||||
)),
|
||||
}));
|
||||
|
||||
jest.mock('../../../hooks/paging/usePaging', () => ({
|
||||
usePaging: jest.fn().mockReturnValue({
|
||||
currentPage: 1,
|
||||
pageSize: 15,
|
||||
paging: { total: 2 },
|
||||
handlePagingChange: jest.fn(),
|
||||
handlePageChange: jest.fn(),
|
||||
handlePageSizeChange: jest.fn(),
|
||||
showPagination: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('../../../context/PermissionProvider/PermissionProvider', () => ({
|
||||
usePermissionProvider: jest.fn().mockReturnValue({
|
||||
getEntityPermissionByFqn: jest.fn().mockResolvedValue({
|
||||
Create: true,
|
||||
Delete: true,
|
||||
ViewAll: true,
|
||||
ViewBasic: true,
|
||||
EditAll: true,
|
||||
}),
|
||||
permissions: {
|
||||
testDefinition: {
|
||||
Create: true,
|
||||
Delete: true,
|
||||
ViewAll: true,
|
||||
ViewBasic: true,
|
||||
EditAll: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('../../Modals/EntityDeleteModal/EntityDeleteModal', () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn().mockImplementation(({ visible, onConfirm, onCancel }) =>
|
||||
visible ? (
|
||||
<div data-testid="entity-delete-modal">
|
||||
<button onClick={onCancel}>Cancel</button>
|
||||
<button onClick={onConfirm}>Confirm</button>
|
||||
</div>
|
||||
) : null
|
||||
),
|
||||
}));
|
||||
|
||||
describe('TestDefinitionList Component', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should render component with test definitions table', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('test-definition-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByText('Column Values To Be Not Null')
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('Table Row Count To Be Between')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render all table columns', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
const tableHeaders = screen.getAllByRole('columnheader');
|
||||
const labels = tableHeaders.map((header) => header.textContent);
|
||||
|
||||
expect(labels).toContain('label.name');
|
||||
expect(labels).toContain('label.description');
|
||||
expect(labels).toContain('label.entity-type');
|
||||
expect(labels).toContain('label.test-platform-plural');
|
||||
expect(labels).toContain('label.enabled');
|
||||
expect(labels).toContain('label.action-plural');
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch test definitions on mount', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getListTestDefinitions).toHaveBeenCalledWith({
|
||||
after: undefined,
|
||||
before: undefined,
|
||||
limit: 15,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should render enabled switch for each test definition', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
const switches = await screen.findAllByRole('switch');
|
||||
|
||||
expect(switches).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should call patchTestDefinition when enable switch is toggled', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('test-definition-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const switches = await screen.findAllByRole('switch');
|
||||
fireEvent.click(switches[1]);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(patchTestDefinition).toHaveBeenCalled();
|
||||
expect(showSuccessToast).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render edit and delete action buttons', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
const editButtons = await screen.findAllByTestId(/edit-test-definition-/);
|
||||
const deleteButtons = await screen.findAllByTestId(
|
||||
/delete-test-definition-/
|
||||
);
|
||||
|
||||
expect(editButtons).toHaveLength(2);
|
||||
expect(deleteButtons).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should open form drawer when edit button is clicked', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
const editButtons = screen.getAllByTestId(/edit-test-definition-/);
|
||||
fireEvent.click(editButtons[0]);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('test-definition-form')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show delete confirmation modal when delete button is clicked', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
const deleteButtons = screen.getAllByTestId(/delete-test-definition-/);
|
||||
fireEvent.click(deleteButtons[0]);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('entity-delete-modal')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call deleteTestDefinitionByFqn when delete is confirmed', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
const deleteButtons = screen.getAllByTestId(/delete-test-definition-/);
|
||||
fireEvent.click(deleteButtons[0]);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const confirmButton = screen.getByText('Confirm');
|
||||
fireEvent.click(confirmButton);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(deleteTestDefinitionByFqn).toHaveBeenCalledWith(
|
||||
'columnValuesToBeNotNull'
|
||||
);
|
||||
expect(showSuccessToast).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render add test definition button', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByTestId('add-test-definition-button')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should open form drawer when add button is clicked', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
const addButton = await screen.findByTestId('add-test-definition-button');
|
||||
fireEvent.click(addButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('test-definition-form')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error toast when API call fails', async () => {
|
||||
const mockError = new Error('API Error');
|
||||
|
||||
(getListTestDefinitions as jest.Mock).mockRejectedValueOnce(mockError);
|
||||
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(showErrorToast).toHaveBeenCalledWith(mockError);
|
||||
});
|
||||
});
|
||||
|
||||
it('should refresh list after successful create/update', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
const addButton = await screen.findByTestId('add-test-definition-button');
|
||||
fireEvent.click(addButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('test-definition-form')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const initialCallCount = (getListTestDefinitions as jest.Mock).mock.calls
|
||||
.length;
|
||||
|
||||
const onSuccessCallback = (TestDefinitionForm as jest.Mock).mock.calls[0][0]
|
||||
.onSuccess;
|
||||
onSuccessCallback();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getListTestDefinitions).toHaveBeenCalledTimes(
|
||||
initialCallCount + 1
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable edit and delete buttons for System test definitions', async () => {
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
const editButtons = screen.getAllByTestId(/edit-test-definition-/);
|
||||
const deleteButtons = screen.getAllByTestId(/delete-test-definition-/);
|
||||
|
||||
// First definition is User provider - should be enabled
|
||||
expect(editButtons[0]).not.toBeDisabled();
|
||||
expect(deleteButtons[0]).not.toBeDisabled();
|
||||
|
||||
// Second definition is System provider - should be disabled
|
||||
expect(editButtons[1]).toBeDisabled();
|
||||
expect(deleteButtons[1]).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not fetch permissions for System test definitions', async () => {
|
||||
const mockGetEntityPermissionByFqn = jest.fn().mockResolvedValue({
|
||||
Create: true,
|
||||
Delete: true,
|
||||
ViewAll: true,
|
||||
ViewBasic: true,
|
||||
EditAll: true,
|
||||
});
|
||||
|
||||
const { usePermissionProvider } = jest.requireMock(
|
||||
'../../../context/PermissionProvider/PermissionProvider'
|
||||
);
|
||||
|
||||
(usePermissionProvider as jest.Mock).mockReturnValue({
|
||||
getEntityPermissionByFqn: mockGetEntityPermissionByFqn,
|
||||
permissions: {
|
||||
testDefinition: {
|
||||
Create: true,
|
||||
Delete: true,
|
||||
ViewAll: true,
|
||||
ViewBasic: true,
|
||||
EditAll: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
await waitFor(() => {
|
||||
// Permissions fetched for all definitions (including system)
|
||||
expect(mockGetEntityPermissionByFqn).toHaveBeenCalledTimes(2);
|
||||
expect(mockGetEntityPermissionByFqn).toHaveBeenCalledWith(
|
||||
ResourceEntity.TEST_DEFINITION,
|
||||
'columnValuesToBeNotNull'
|
||||
);
|
||||
expect(mockGetEntityPermissionByFqn).toHaveBeenCalledWith(
|
||||
ResourceEntity.TEST_DEFINITION,
|
||||
'tableRowCountToBeBetween'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable enabled switch when user lacks EditAll permission', async () => {
|
||||
const { usePermissionProvider } = jest.requireMock(
|
||||
'../../../context/PermissionProvider/PermissionProvider'
|
||||
);
|
||||
|
||||
(usePermissionProvider as jest.Mock).mockReturnValue({
|
||||
getEntityPermissionByFqn: jest.fn().mockResolvedValue({
|
||||
Create: false,
|
||||
Delete: false,
|
||||
ViewAll: true,
|
||||
ViewBasic: true,
|
||||
EditAll: false,
|
||||
}),
|
||||
permissions: {
|
||||
testDefinition: {
|
||||
Create: true,
|
||||
Delete: true,
|
||||
ViewAll: true,
|
||||
ViewBasic: true,
|
||||
EditAll: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
const switches = await screen.findAllByRole('switch');
|
||||
|
||||
// First definition should be disabled due to lack of EditAll permission
|
||||
expect(switches[0]).toBeDisabled();
|
||||
});
|
||||
|
||||
it('should enable switch when user has EditAll permission', async () => {
|
||||
const { usePermissionProvider } = jest.requireMock(
|
||||
'../../../context/PermissionProvider/PermissionProvider'
|
||||
);
|
||||
|
||||
(usePermissionProvider as jest.Mock).mockReturnValue({
|
||||
getEntityPermissionByFqn: jest.fn().mockResolvedValue({
|
||||
Create: true,
|
||||
Delete: true,
|
||||
ViewAll: true,
|
||||
ViewBasic: true,
|
||||
EditAll: true,
|
||||
}),
|
||||
permissions: {
|
||||
testDefinition: {
|
||||
Create: true,
|
||||
Delete: true,
|
||||
ViewAll: true,
|
||||
ViewBasic: true,
|
||||
EditAll: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(<TestDefinitionList />, { wrapper: MemoryRouter });
|
||||
|
||||
const switches = await screen.findAllByRole('switch');
|
||||
|
||||
// Both definitions should be enabled with EditAll permission
|
||||
expect(switches[0]).not.toBeDisabled();
|
||||
expect(switches[1]).not.toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
|
@ -95,6 +95,13 @@ export const SIDEBAR_LIST: Array<LeftSidebarItem> = [
|
|||
icon: AlertIcon,
|
||||
dataTestId: `app-bar-item-${SidebarItem.OBSERVABILITY_ALERT}`,
|
||||
},
|
||||
{
|
||||
key: ROUTES.RULES_LIBRARY,
|
||||
title: 'label.rules-library',
|
||||
redirect_url: ROUTES.RULES_LIBRARY,
|
||||
icon: DataQualityIcon,
|
||||
dataTestId: `app-bar-item-rules-library`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ export const ROUTES = {
|
|||
OBSERVABILITY_ALERT_DETAILS_WITH_TAB: `/observability/alert/${PLACEHOLDER_ROUTE_FQN}/${PLACEHOLDER_ROUTE_TAB}`,
|
||||
ADD_OBSERVABILITY_ALERTS: '/observability/alerts/add',
|
||||
EDIT_OBSERVABILITY_ALERTS: `/observability/alerts/edit/${PLACEHOLDER_ROUTE_FQN}`,
|
||||
RULES_LIBRARY: '/rules-library',
|
||||
|
||||
// Notification Alerts
|
||||
NOTIFICATIONS: `/settings/${GlobalSettingsMenuCategory.NOTIFICATIONS}`,
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ export enum Operation {
|
|||
EditStatus = "EditStatus",
|
||||
EditTags = "EditTags",
|
||||
EditTeams = "EditTeams",
|
||||
EditTestDefinitionLibrary = "EditTestDefinitionLibrary",
|
||||
EditTests = "EditTests",
|
||||
EditTier = "EditTier",
|
||||
EditUsage = "EditUsage",
|
||||
|
|
@ -200,6 +201,7 @@ export enum Operation {
|
|||
ViewSampleData = "ViewSampleData",
|
||||
ViewScim = "ViewScim",
|
||||
ViewTestCaseFailedRowsSample = "ViewTestCaseFailedRowsSample",
|
||||
ViewTestDefinitionLibrary = "ViewTestDefinitionLibrary",
|
||||
ViewTests = "ViewTests",
|
||||
ViewUsage = "ViewUsage",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
* Schema corresponding to a Test Definition
|
||||
*/
|
||||
export interface CreateTestDefinition {
|
||||
dataQualityDimension?: DataQualityDimensions;
|
||||
/**
|
||||
* Description of the testcase.
|
||||
*/
|
||||
|
|
@ -37,7 +38,13 @@ export interface CreateTestDefinition {
|
|||
owners?: EntityReference[];
|
||||
parameterDefinition?: TestCaseParameterDefinition[];
|
||||
provider?: ProviderType;
|
||||
supportedDataTypes?: DataType[];
|
||||
/**
|
||||
* SQL expression template for custom SQL-based test definitions. Supports substitution
|
||||
* variables: {table} and {column} for runtime entity references, and {{paramName}} for
|
||||
* user-defined parameters.
|
||||
*/
|
||||
sqlExpression?: string;
|
||||
supportedDataTypes?: DataType[];
|
||||
/**
|
||||
* List of services that this test definition supports. When empty, it implies all services
|
||||
* are supported.
|
||||
|
|
@ -46,6 +53,20 @@ export interface CreateTestDefinition {
|
|||
testPlatforms: TestPlatform[];
|
||||
}
|
||||
|
||||
/**
|
||||
* This enum defines the dimension a test case belongs to.
|
||||
*/
|
||||
export enum DataQualityDimensions {
|
||||
Accuracy = "Accuracy",
|
||||
Completeness = "Completeness",
|
||||
Consistency = "Consistency",
|
||||
Integrity = "Integrity",
|
||||
NoDimension = "NoDimension",
|
||||
SQL = "SQL",
|
||||
Uniqueness = "Uniqueness",
|
||||
Validity = "Validity",
|
||||
}
|
||||
|
||||
/**
|
||||
* This enum defines the type for which this test definition applies to.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ export enum Operation {
|
|||
EditStatus = "EditStatus",
|
||||
EditTags = "EditTags",
|
||||
EditTeams = "EditTeams",
|
||||
EditTestDefinitionLibrary = "EditTestDefinitionLibrary",
|
||||
EditTests = "EditTests",
|
||||
EditTier = "EditTier",
|
||||
EditUsage = "EditUsage",
|
||||
|
|
@ -82,6 +83,7 @@ export enum Operation {
|
|||
ViewSampleData = "ViewSampleData",
|
||||
ViewScim = "ViewScim",
|
||||
ViewTestCaseFailedRowsSample = "ViewTestCaseFailedRowsSample",
|
||||
ViewTestDefinitionLibrary = "ViewTestDefinitionLibrary",
|
||||
ViewTests = "ViewTests",
|
||||
ViewUsage = "ViewUsage",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ export enum Operation {
|
|||
EditStatus = "EditStatus",
|
||||
EditTags = "EditTags",
|
||||
EditTeams = "EditTeams",
|
||||
EditTestDefinitionLibrary = "EditTestDefinitionLibrary",
|
||||
EditTests = "EditTests",
|
||||
EditTier = "EditTier",
|
||||
EditUsage = "EditUsage",
|
||||
|
|
@ -124,6 +125,7 @@ export enum Operation {
|
|||
ViewSampleData = "ViewSampleData",
|
||||
ViewScim = "ViewScim",
|
||||
ViewTestCaseFailedRowsSample = "ViewTestCaseFailedRowsSample",
|
||||
ViewTestDefinitionLibrary = "ViewTestDefinitionLibrary",
|
||||
ViewTests = "ViewTests",
|
||||
ViewUsage = "ViewUsage",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ export enum Operation {
|
|||
EditStatus = "EditStatus",
|
||||
EditTags = "EditTags",
|
||||
EditTeams = "EditTeams",
|
||||
EditTestDefinitionLibrary = "EditTestDefinitionLibrary",
|
||||
EditTests = "EditTests",
|
||||
EditTier = "EditTier",
|
||||
EditUsage = "EditUsage",
|
||||
|
|
@ -107,6 +108,7 @@ export enum Operation {
|
|||
ViewSampleData = "ViewSampleData",
|
||||
ViewScim = "ViewScim",
|
||||
ViewTestCaseFailedRowsSample = "ViewTestCaseFailedRowsSample",
|
||||
ViewTestDefinitionLibrary = "ViewTestDefinitionLibrary",
|
||||
ViewTests = "ViewTests",
|
||||
ViewUsage = "ViewUsage",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ export enum Operation {
|
|||
EditStatus = "EditStatus",
|
||||
EditTags = "EditTags",
|
||||
EditTeams = "EditTeams",
|
||||
EditTestDefinitionLibrary = "EditTestDefinitionLibrary",
|
||||
EditTests = "EditTests",
|
||||
EditTier = "EditTier",
|
||||
EditUsage = "EditUsage",
|
||||
|
|
@ -352,6 +353,7 @@ export enum Operation {
|
|||
ViewSampleData = "ViewSampleData",
|
||||
ViewScim = "ViewScim",
|
||||
ViewTestCaseFailedRowsSample = "ViewTestCaseFailedRowsSample",
|
||||
ViewTestDefinitionLibrary = "ViewTestDefinitionLibrary",
|
||||
ViewTests = "ViewTests",
|
||||
ViewUsage = "ViewUsage",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,12 @@ export interface TestDefinition {
|
|||
* Domains the asset belongs to. When not set, the asset inherits the domain from the parent
|
||||
* it belongs to.
|
||||
*/
|
||||
domains?: EntityReference[];
|
||||
domains?: EntityReference[];
|
||||
/**
|
||||
* When `true` indicates the test definition is available for creating test cases. System
|
||||
* test definitions can only be disabled by users with appropriate permissions.
|
||||
*/
|
||||
enabled?: boolean;
|
||||
entityType?: EntityType;
|
||||
/**
|
||||
* FullyQualifiedName same as `name`.
|
||||
|
|
@ -64,7 +69,15 @@ export interface TestDefinition {
|
|||
owners?: EntityReference[];
|
||||
parameterDefinition?: TestCaseParameterDefinition[];
|
||||
provider?: ProviderType;
|
||||
supportedDataTypes?: DataType[];
|
||||
/**
|
||||
* SQL expression template for custom SQL-based test definitions. Supports substitution
|
||||
* variables: {table} and {column} for runtime entity references, and {{paramName}} for
|
||||
* user-defined parameters. This field is only applicable for test definitions with
|
||||
* testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data
|
||||
* quality validation.
|
||||
*/
|
||||
sqlExpression?: string;
|
||||
supportedDataTypes?: DataType[];
|
||||
/**
|
||||
* List of services that this test definition supports. When empty, it implies all services
|
||||
* are supported.
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "مقاييس محلل البيانات",
|
||||
"data-proportion-plural": "نسب البيانات",
|
||||
"data-quality": "جودة البيانات",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "اختبار جودة البيانات",
|
||||
"data-quality-test-plural": "اختبارات جودة البيانات",
|
||||
"data-quartile-plural": "رباعيات البيانات",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "أدخل وحدة قياس مخصصة واضغط زر الإدخال",
|
||||
"enter-each-value-and-press-enter": "أدخل كل قيمة ثم اضغط Enter",
|
||||
"enter-entity": "أدخل {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "أدخل اسم {{entity}}",
|
||||
"enter-entity-value": "أدخل قيمة {{entity}}",
|
||||
"enter-field-description": "أدخل وصف {{field}}",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "الصفحة غير موجودة",
|
||||
"page-views-by-data-asset-plural": "مشاهدات الصفحة حسب أصول البيانات",
|
||||
"parameter": "معامل",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "معاملات",
|
||||
"parent": "الأصل",
|
||||
"parsing-timeout-limit": "حد مهلة تحليل الاستعلام",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "طريقة الطلب",
|
||||
"request-schema-field": "حقل مخطط الطلب",
|
||||
"request-tag-plural": "طلب وسوم",
|
||||
"required": "Required",
|
||||
"requirement-plural": "متطلبات",
|
||||
"reset": "إعادة تعيين",
|
||||
"reset-default-layout": "إعادة تعيين التخطيط الافتراضي",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- القاعدة: {{ruleName}}",
|
||||
"rules-count": "({{count}} قواعد)",
|
||||
"rules-evaluated": "القواعد التي تم تقييمها",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "تشغيل",
|
||||
"run-agent-plural": "تشغيل الوكلاء",
|
||||
"run-at": "تشغيل في",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "أصول بيانات محددة",
|
||||
"spreadsheet": "جدول بيانات",
|
||||
"spreadsheet-plural": "جداول بيانات",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "دالة SQL",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "استعلام SQL",
|
||||
"sso": "SSO",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "الأحد",
|
||||
"support": "دعم",
|
||||
"support-url": "رابط الدعم",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "اللغات المدعومة",
|
||||
"switch-persona": "تبديل الشخصية",
|
||||
"sync-alert-offset": "مزامنة التنبيه",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "حالات اختبار",
|
||||
"test-case-resolution-status": "حالة قرار حالة الاختبار",
|
||||
"test-case-result": "نتائج حالة الاختبار",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "اختبار البريد الإلكتروني",
|
||||
"test-email-connection": "اختبار اتصال البريد الإلكتروني",
|
||||
"test-entity": "اختبار {{entity}}",
|
||||
"test-level-lowercase": "مستوى الاختبار",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "اختبارات",
|
||||
"test-plural-type": "{{type}} اختبارات",
|
||||
"test-suite": "مجموعة اختبار",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "استيعاب البيانات الوصفية من خدمات التخزين الأكثر شيوعًا.",
|
||||
"page-sub-header-for-table-profile": "راقب وافهم هيكل جداولك باستخدام المُحلل (profiler).",
|
||||
"page-sub-header-for-teams": "مثل هيكلك التنظيمي بالكامل بفرق هرمية.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "عرض وإدارة المستخدمين العاديين في مؤسستك. بالنسبة للمستخدمين المسؤولين، يرجى زيارة صفحة المسؤول.",
|
||||
"paid-addon-description": "<0>{{app}}</0> هو إضافة مدفوعة لعملاء Collate.",
|
||||
"passed-x-checks": "اجتاز {{count}} من عمليات التحقق",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "لإضافة مرادف، ما عليك سوى كتابته والضغط على Enter",
|
||||
"system-alert-edit-message": "لا يُسمح بتحرير تنبيه تم إنشاؤه بواسطة النظام.",
|
||||
"system-tag-delete-disable-message": "لا يُسمح بحذف علامات تم إنشاؤها بواسطة النظام. يمكنك محاولة تعطيل العلامة بدلاً من ذلك.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "هل ترغب في المتابعة بتحديث العلامات؟",
|
||||
"tailor-experience-for-persona": "صمم التجربة خصيصًا لشخصية {{persona}}، فقط جربها!",
|
||||
"take-quick-product-tour": "قم بجولة سريعة في المنتج لتبدأ!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "افتراضي",
|
||||
"withIp": " من {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "اختبر اتصالاتك قبل إنشاء الخدمة",
|
||||
"testing-your-connection-may-take-two-minutes": "قد يستغرق اختبار اتصالاتك ما يصل إلى دقيقتين",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "هذا الإجراء غير مسموح به للكيانات المحذوفة.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "تم حذف {{count}} {{entity}}s بنجاح",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" موجود بالفعل. لا يُسمح بتكرار {{entityPlural}}.",
|
||||
"entity-already-exist-message-without-name": "يوجد بالفعل {{entity}} بالتفاصيل المُعطاة. لا يُسمح بتكرار {{entityPlural}}.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "خطأ أثناء إنشاء {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "تم حذف \"{{entity}}\" بنجاح!",
|
||||
"entity-details-fetch-error": "خطأ أثناء جلب التفاصيل لـ {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "خطأ أثناء جلب عدد موجز الكيان!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "تم الوصول إلى حد {{entity}}",
|
||||
"entity-removing-error": "خطأ أثناء إزالة {{entity}}",
|
||||
"entity-unfollow-error": "خطأ أثناء إلغاء متابعة {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "خطأ أثناء تحديث {{entity}}",
|
||||
"error-selected-node-name-details": "خطأ أثناء الحصول على تفاصيل {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "خطأ أثناء تجديد رمز الهوية المميز من Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "تم حل المهمة بنجاح",
|
||||
"team-moved-error": "خطأ أثناء نقل الفريق",
|
||||
"test-connection-error": "خطأ أثناء اختبار الاتصال!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "لا يمكن التراجع عن هذا الإجراء.",
|
||||
"unauthorized-user": "مستخدم غير مصرح به! يرجى التحقق من البريد الإلكتروني أو كلمة المرور",
|
||||
"unexpected-error": "حدث خطأ غير متوقع.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Data Profiler Metriken",
|
||||
"data-proportion-plural": "Datenverhältnisse",
|
||||
"data-quality": "Datenqualität",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Datenqualitätstest",
|
||||
"data-quality-test-plural": "Datenqualitätstests",
|
||||
"data-quartile-plural": "Datenquartile",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Geben Sie die benutzerdefinierte Maßeinheit ein und drücken Sie Enter",
|
||||
"enter-each-value-and-press-enter": "Geben Sie jeden Wert ein und drücken Sie die Eingabetaste",
|
||||
"enter-entity": "{{entity}} eingeben",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "Geben Sie einen Namen für {{entity}} ein",
|
||||
"enter-entity-value": "Enter {{entity}} Value",
|
||||
"enter-field-description": "Geben Sie eine Beschreibung für {{field}} ein",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Seite nicht gefunden",
|
||||
"page-views-by-data-asset-plural": "Seitenaufrufe nach Datenanlage",
|
||||
"parameter": "Parameter",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Parameter",
|
||||
"parent": "Übergeordnet",
|
||||
"parsing-timeout-limit": "Analyse-Timeout-Limit",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Anfrage Methode",
|
||||
"request-schema-field": "Anfrage Feld Schema",
|
||||
"request-tag-plural": "Tag-Anfragen",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Anforderungen",
|
||||
"reset": "Zurücksetzen",
|
||||
"reset-default-layout": "Standard Layout zurücksetzen",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Regel: {{ruleName}}",
|
||||
"rules-count": "({{count}} Regeln)",
|
||||
"rules-evaluated": "Regeln ausgewertet",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Ausführen",
|
||||
"run-agent-plural": "Agenten ausführen",
|
||||
"run-at": "Ausführen um",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Spezifische Datenbestände",
|
||||
"spreadsheet": "Tabellenkalkulation",
|
||||
"spreadsheet-plural": "Tabellenkalkulationen",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL-Funktion",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL-Abfrage",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "Sonntag",
|
||||
"support": "Unterstützung",
|
||||
"support-url": "Support-URL",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Unterstützte Sprachen",
|
||||
"switch-persona": "Persona wechseln",
|
||||
"sync-alert-offset": "Warnung synchronisieren",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Testfälle",
|
||||
"test-case-resolution-status": "Testfall-Auflösungsstatus",
|
||||
"test-case-result": "Testfall Ergebnisse",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "Test Email",
|
||||
"test-email-connection": "Email-Connection testen",
|
||||
"test-entity": "{{entity}}-Test",
|
||||
"test-level-lowercase": "testebene",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Tests",
|
||||
"test-plural-type": "{{type}}-Tests",
|
||||
"test-suite": "Test-Suite",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "Ingestion von Metadaten aus den am häufigsten verwendeten Speicherdiensten.",
|
||||
"page-sub-header-for-table-profile": "Überwache und verstehe die Struktur deiner Tabellen mit dem Profiler.",
|
||||
"page-sub-header-for-teams": "Stelle deine gesamte Organisationsstruktur mit hierarchischen Teams dar.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "Verwalten Sie reguläre Benutzer in Ihrer Organisation. Für Administratoren besuchen Sie bitte die Administratorseite.",
|
||||
"paid-addon-description": "<0>{{app}}</0> ist ein kostenpflichtiges Add-on für Collate-Kunden.",
|
||||
"passed-x-checks": "{{count}} Prüfungen bestanden",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "Um ein Synonym hinzuzufügen, geben Sie es einfach ein und drücken Sie Enter",
|
||||
"system-alert-edit-message": "Das Bearbeiten eines systemgenerierten Alarms ist nicht erlaubt.",
|
||||
"system-tag-delete-disable-message": "Das Löschen von systemgenerierten Tags ist nicht zulässig. Sie können versuchen, den Tag stattdessen zu deaktivieren.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "Möchten Sie mit der Aktualisierung der Tags fortfahren?",
|
||||
"tailor-experience-for-persona": "Passen Sie die Erfahrung speziell für das {{persona}}-Persona an, probieren Sie es aus!",
|
||||
"take-quick-product-tour": "Machen Sie eine Produkttour, um loszulegen!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Bitte stellen Sie sicher, dass {{service_type}} so konfiguriert ist, dass Verbindungen erlaubt sind",
|
||||
"withIp": " von {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Testen Sie Ihre Verbindungen, bevor Sie den Dienst erstellen",
|
||||
"testing-your-connection-may-take-two-minutes": "Das Testen Ihrer Verbindungen kann bis zu 2 Minuten dauern",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "Diese Aktion ist für gelöschte Entitäten nicht erlaubt.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "{{count}} {{entity}}s erfolgreich gelöscht",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" existiert bereits. Duplizierte {{entityPlural}} sind nicht erlaubt.",
|
||||
"entity-already-exist-message-without-name": "Ein {{entity}} mit den angegebenen Details existiert bereits. Duplizierte {{entityPlural}} sind nicht erlaubt.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "Fehler beim Erstellen von {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "{{entity}} erfolgreich gelöscht!",
|
||||
"entity-details-fetch-error": "Fehler beim Abrufen von Details für {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "Fehler beim Abrufen der Anzahl der Entitätsnachrichten!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} Limit erreicht",
|
||||
"entity-removing-error": "Fehler beim Entfernen von {{entity}}",
|
||||
"entity-unfollow-error": "Fehler beim Nicht-Folgen von {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "Fehler beim Aktualisieren von {{entity}}",
|
||||
"error-selected-node-name-details": "Fehler beim Abrufen von Details für {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "Fehler beim Erneuern des ID-Tokens von Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Aufgabe erfolgreich gelöst",
|
||||
"team-moved-error": "Fehler beim Verschieben des Teams",
|
||||
"test-connection-error": "Fehler beim Testen der Verbindung!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "Unbefugter Benutzer! Bitte überprüfen Sie E-Mail oder Passwort.",
|
||||
"unexpected-error": "Ein unerwarteter Fehler ist aufgetreten.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Data Profiler Metrics",
|
||||
"data-proportion-plural": "Data Proportions",
|
||||
"data-quality": "Data Quality",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Data Quality Test",
|
||||
"data-quality-test-plural": "Data Quality Tests",
|
||||
"data-quartile-plural": "Data Quartiles",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Enter Custom Measurement Unit and Press Enter",
|
||||
"enter-each-value-and-press-enter": "Enter each value and press Enter",
|
||||
"enter-entity": "Enter {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "Enter {{entity}} name",
|
||||
"enter-entity-value": "Enter {{entity}} Value",
|
||||
"enter-field-description": "Enter {{field}} description",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Page Not Found",
|
||||
"page-views-by-data-asset-plural": "Page Views by Data Assets",
|
||||
"parameter": "Parameter",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Parameters",
|
||||
"parent": "Parent",
|
||||
"parsing-timeout-limit": "Query Parsing Timeout Limit",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Request Method",
|
||||
"request-schema-field": "Request Schema Field",
|
||||
"request-tag-plural": "Request Tags",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Requirements",
|
||||
"reset": "Reset",
|
||||
"reset-default-layout": "Reset Default Layout",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Rules Evaluated",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Run",
|
||||
"run-agent-plural": "Run Agents",
|
||||
"run-at": "Run at",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Specific Data Assets",
|
||||
"spreadsheet": "Spreadsheet",
|
||||
"spreadsheet-plural": "Spreadsheets",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL Function",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL Query",
|
||||
"sso": "SSO",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "Sunday",
|
||||
"support": "Support",
|
||||
"support-url": "Support URL",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Supported Languages",
|
||||
"switch-persona": "Switch Persona",
|
||||
"sync-alert-offset": "Sync Alert",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Test Cases",
|
||||
"test-case-resolution-status": "Test Case Resolution Status",
|
||||
"test-case-result": "Test Case Results",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "Test Email",
|
||||
"test-email-connection": "Test Email Connection",
|
||||
"test-entity": "Test {{entity}}",
|
||||
"test-level-lowercase": "test level",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Tests",
|
||||
"test-plural-type": "{{type}} Tests",
|
||||
"test-suite": "Test Suite",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "Ingest metadata from the most popular storage services.",
|
||||
"page-sub-header-for-table-profile": "Monitor and understand your tables structure with the profiler.",
|
||||
"page-sub-header-for-teams": "Represent your entire organizational structure with hierarchical teams.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "View and manage regular users in your organization. For admin users, please visit the Admin page.",
|
||||
"paid-addon-description": "<0>{{app}}</0> is a paid add-on for Collate customers.",
|
||||
"passed-x-checks": "Passed {{count}} checks",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "To add a synonym, simply type it in and press Enter",
|
||||
"system-alert-edit-message": "Editing a system generated alert is not allowed.",
|
||||
"system-tag-delete-disable-message": "Deleting a system generated tags is not allowed. You can try disabling the tag instead.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "Would you like to proceed with updating the tags?",
|
||||
"tailor-experience-for-persona": "Tailor the experience specifically for the {{persona}} persona, just give it a spin!",
|
||||
"take-quick-product-tour": "Take a product tour to get started!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Please ensure that {{service_type}} is configured to allow connections",
|
||||
"withIp": " from {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Test your connections before creating the service",
|
||||
"testing-your-connection-may-take-two-minutes": "Testing your connections may take up-to 2 minutes",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "This action is not allowed for deleted entities.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "Successfully deleted {{count}} {{entity}}s",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" already exists. Duplicated {{entityPlural}} are not allowed.",
|
||||
"entity-already-exist-message-without-name": "A {{entity}} with the given details already exists. Duplicated {{entityPlural}} are not allowed.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "Error while creating {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "\"{{entity}}\" deleted successfully!",
|
||||
"entity-details-fetch-error": "Error while fetching details for {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "Error while fetching entity feed count!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} limit reached",
|
||||
"entity-removing-error": "Error while removing {{entity}}",
|
||||
"entity-unfollow-error": "Error while unfollowing {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "Error while updating {{entity}}",
|
||||
"error-selected-node-name-details": "Error while getting {{selectedNodeName}} details",
|
||||
"error-while-renewing-id-token-with-message": "Error while renewing id token from Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Task resolved successfully",
|
||||
"team-moved-error": "Error while moving team",
|
||||
"test-connection-error": "Error while testing connection!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "UnAuthorized user! please check email or password",
|
||||
"unexpected-error": "An unexpected error occurred.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Métricas de perfilado",
|
||||
"data-proportion-plural": "Proporciones de datos",
|
||||
"data-quality": "Tests de calidad",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Test de calidad de datos",
|
||||
"data-quality-test-plural": "Pruebas de Calidad de Datos",
|
||||
"data-quartile-plural": "cuartiles",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Introduce la unidad de medida personalizada y pulsa Enter",
|
||||
"enter-each-value-and-press-enter": "Introduzca cada valor y presione Enter",
|
||||
"enter-entity": "Ingrese {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "Ingrese el nombre de {{entity}}",
|
||||
"enter-entity-value": "Ingrese valor de {{entity}}",
|
||||
"enter-field-description": "Ingrese la descripción de {{field}}",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Página no encontrada",
|
||||
"page-views-by-data-asset-plural": "Vistas de página por activos de datos",
|
||||
"parameter": "Parámetro",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Parámetros",
|
||||
"parent": "Padre",
|
||||
"parsing-timeout-limit": "Límite Tiempo de Espera de Análisis de Consultas",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Petición Método",
|
||||
"request-schema-field": "Petición Campo del Esquema",
|
||||
"request-tag-plural": "Etiquetas de solicitud",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Requisitos",
|
||||
"reset": "Restablecer",
|
||||
"reset-default-layout": "Restablecer el panel por defecto",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Regla: {{ruleName}}",
|
||||
"rules-count": "({{count}} reglas)",
|
||||
"rules-evaluated": "Reglas Evaluadas",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Ejecutar",
|
||||
"run-agent-plural": "Ejecutar Agentes",
|
||||
"run-at": "Ejecutar a las",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Activos de Datos Específicos",
|
||||
"spreadsheet": "Hoja de cálculo",
|
||||
"spreadsheet-plural": "Hojas de cálculo",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "Función SQL",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "Consulta SQL",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "Domingo",
|
||||
"support": "Soporte",
|
||||
"support-url": "URL de soporte",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Idiomas soportados",
|
||||
"switch-persona": "Cambiar Persona",
|
||||
"sync-alert-offset": "Sincronizar alerta",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Casos de Prueba",
|
||||
"test-case-resolution-status": "Estado de Resolución del Caso de Prueba",
|
||||
"test-case-result": "Resultados del caso de prueba",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "Email de prueba",
|
||||
"test-email-connection": "Probar conexión de email",
|
||||
"test-entity": "Prueba {{entity}}",
|
||||
"test-level-lowercase": "nivel de prueba",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Pruebas",
|
||||
"test-plural-type": "Pruebas de {{type}}",
|
||||
"test-suite": "Suite de Pruebas",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "Ingresa metadatos desde los servicios de almacenamiento más populares.",
|
||||
"page-sub-header-for-table-profile": "Monitorea y comprende la estructura de tus tablas con el perfilador.",
|
||||
"page-sub-header-for-teams": "Representa toda la estructura organizativa con equipos jerárquicos.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "Gestione los usuarios regulares en su organización. Para administradores, visite la página de Administradores.",
|
||||
"paid-addon-description": "<0>{{app}}</0> es un complemento (add-on) de pago para clientes de Collate.",
|
||||
"passed-x-checks": "Pasaron {{count}} verificaciones",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "Para agregar un sinónimo, simplemente escríbelo y presiona Enter",
|
||||
"system-alert-edit-message": "No está permitido editar una alerta generada por el sistema.",
|
||||
"system-tag-delete-disable-message": "No se permite eliminar una etiqueta generada por el sistema. Puedes intentar desactivar la etiqueta en su lugar.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "¿Le gustaría proceder con la actualización de etiquetas?",
|
||||
"tailor-experience-for-persona": "¡Adapte la experiencia específicamente para el persona {{persona}}, pruébelo!",
|
||||
"take-quick-product-tour": "¡Realiza un recorrido rápido del producto para comenzar!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Por favor, asegúrese de que {{service_type}} esté configurado para permitir conexiones",
|
||||
"withIp": " desde {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Prueba la conexión antes de crear el servicio",
|
||||
"testing-your-connection-may-take-two-minutes": "Probar la conexión puede tardar hasta 2 minutos",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "Esta acción no está permitida para entidades eliminadas.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "{{count}} {{entity}}s eliminados exitosamente",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" ya existe. No se permiten {{entity}} duplicados.",
|
||||
"entity-already-exist-message-without-name": "Un {{entity}} con los detalles proporcionados ya existe. No se permiten duplicados de {{entityPlural}}.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "Error al crear {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "¡{{entity}} eliminado exitosamente!",
|
||||
"entity-details-fetch-error": "Error al recuperar detalles para {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "¡Error al obtener el recuento de alimentación de la entidad!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "Límite de {{entity}} alcanzado",
|
||||
"entity-removing-error": "Error al eliminar {{entity}}",
|
||||
"entity-unfollow-error": "Error al dejar de seguir {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "Error al actualizar {{entity}}",
|
||||
"error-selected-node-name-details": "Error al obstener detalles de {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "Error al renovar el token de identificación desde Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Tarea resuelta con éxito.",
|
||||
"team-moved-error": "Error al mover el equipo.",
|
||||
"test-connection-error": "Error al probar la conexión.",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "¡Usuario no autorizado! Por favor revise el correo electrónico o la contraseña.",
|
||||
"unexpected-error": "Se produjo un error inesperado.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Métriques du Profileur de Données",
|
||||
"data-proportion-plural": "Proportions des Données",
|
||||
"data-quality": "Qualité des Données",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Test de Qualité des Données",
|
||||
"data-quality-test-plural": "Tests de Qualité des Données",
|
||||
"data-quartile-plural": "Quartiles des Données",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Entrez l'unité de mesure personnalisée et appuyez sur Entrée",
|
||||
"enter-each-value-and-press-enter": "Entrez chaque valeur et appuyez sur Entrée",
|
||||
"enter-entity": "Entrer {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "Entrer un nom pour {{entity}}",
|
||||
"enter-entity-value": "Entrer une valeur pour {{entity}}",
|
||||
"enter-field-description": "Entrer une description pour {{field}}",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Page Non Trouvée",
|
||||
"page-views-by-data-asset-plural": "Vues de Page par Actif de Données",
|
||||
"parameter": "Paramètre",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Paramètres",
|
||||
"parent": "Parent",
|
||||
"parsing-timeout-limit": "Limite de Temps d'Analyse de Requête",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Méthode de Requête",
|
||||
"request-schema-field": "Champ de Schéma de Requête",
|
||||
"request-tag-plural": "Demander l'ajout de tags",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Critères",
|
||||
"reset": "Réinitialiser",
|
||||
"reset-default-layout": "Réinitialiser la Disposition par Défaut",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Règles Évaluées",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Exécuter",
|
||||
"run-agent-plural": "Exécuter les Agents",
|
||||
"run-at": "Exécuté à",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Actifs de Données Spécifiques",
|
||||
"spreadsheet": "Feuille de calcul",
|
||||
"spreadsheet-plural": "Feuilles de calcul",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "Fonction SQL",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "Requête SQL",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "Dimanche",
|
||||
"support": "Support",
|
||||
"support-url": "URL de Support",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Languages Supportés",
|
||||
"switch-persona": "Changer de Persona",
|
||||
"sync-alert-offset": "Synchroniser l'alerte",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Cas de Tests",
|
||||
"test-case-resolution-status": "Statut de Résolution du Cas de Test",
|
||||
"test-case-result": "Résultat du cas de test",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "Test Email",
|
||||
"test-email-connection": "Tester la connexion Email",
|
||||
"test-entity": "Test {{entity}}",
|
||||
"test-level-lowercase": "niveau de test",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Tests",
|
||||
"test-plural-type": "Tests {{type}}",
|
||||
"test-suite": "Ensemble de Tests",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "Ingestion de métadonnées à partir des services de stockage les plus populaires.",
|
||||
"page-sub-header-for-table-profile": "Surveillez et comprenez la structure de vos tables avec le profilage.",
|
||||
"page-sub-header-for-teams": "Représentez toute la structure organisationnelle avec des équipes hiérarchiques.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "Gérez les utilisateurs réguliers de votre organisation. Pour les administrateurs, visitez la page Administrateurs.",
|
||||
"paid-addon-description": "<0>{{app}}</0> est un add-on payant pour les clients utilisateurs de Collate.",
|
||||
"passed-x-checks": "{{count}} vérifications réussies",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "Pour ajouter un synonyme, tapez-le et appuyez sur Entrée",
|
||||
"system-alert-edit-message": "La modification d'une alerte générée par le système n'est pas autorisée.",
|
||||
"system-tag-delete-disable-message": "Supprimer un tag système n'est pas permis. Tentez plutôt de désactiver ce tag.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "Souhaitez-vous procéder à la mise à jour des étiquettes ?",
|
||||
"tailor-experience-for-persona": "Adaptez l'expérience spécifiquement pour le persona {{persona}}, essayez-le !",
|
||||
"take-quick-product-tour": "Faites une visite guidée pour vous lancer!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Veuillez vérifier que {{service_type}} est configuré pour autoriser les connexions",
|
||||
"withIp": " depuis {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Testez la connexion avant de créer le service",
|
||||
"testing-your-connection-may-take-two-minutes": "Le test de votre connexion peut prendre jusqu'à 2 minutes",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "Cette action n'est pas permise pour les entités supprimées.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "{{count}} {{entity}}s supprimé(e)s avec succès",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" existe déjà. Les doublons de {{entity}} ne sont pas autorisés.",
|
||||
"entity-already-exist-message-without-name": "Un(e) {{entity}} avec les détails fournis existe déjà. Les doublons de {{entityPlural}} ne sont pas autorisés.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "Erreur lors de la création de {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "{{entity}} supprimé(e) avec succès !",
|
||||
"entity-details-fetch-error": "Erreur lors de la récupération des détails pour {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "Erreur lors de la récupération du nombre d'alimentation de l'entité !",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "Limite atteinte pour {{entity}}",
|
||||
"entity-removing-error": "Erreur lors de la suppression de {{entity}}",
|
||||
"entity-unfollow-error": "Erreur lors de l'arrêt de suivi de {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "Erreur lors de la mise à jour de {{entity}}",
|
||||
"error-selected-node-name-details": "Erreur lors de la récupération des détails de {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "Erreur lors du renouvellement du jeton d'identification à partir d'Auth0 SSO : {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Tâche résolue avec succès",
|
||||
"team-moved-error": "Erreur lors du déplacement de l'équipe",
|
||||
"test-connection-error": "Erreur lors du test de la connexion !",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "Cette action ne peut pas être annulée.",
|
||||
"unauthorized-user": "Utilisateur non autorisé ! Veuillez vérifier votre e-mail ou votre mot de passe",
|
||||
"unexpected-error": "Une erreur inattendue est survenue.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Métricas de perfilador de datos",
|
||||
"data-proportion-plural": "Proporcións de datos",
|
||||
"data-quality": "Calidade dos datos",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Proba de calidade de datos",
|
||||
"data-quality-test-plural": "Pruebas de Calidad de Datos",
|
||||
"data-quartile-plural": "Cuartís de datos",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Introduce a unidade de medida personalizada e preme Enter",
|
||||
"enter-each-value-and-press-enter": "Enter each value and press Enter",
|
||||
"enter-entity": "Introducir {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "Introducir o nome de {{entity}}",
|
||||
"enter-entity-value": "Introducir o valor de {{entity}}",
|
||||
"enter-field-description": "Introducir a descrición de {{field}}",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Páxina non atopada",
|
||||
"page-views-by-data-asset-plural": "Visualizacións de páxinas por activos de datos",
|
||||
"parameter": "Parámetro",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Parámetros",
|
||||
"parent": "Pai",
|
||||
"parsing-timeout-limit": "Límite de tempo de análise de consultas",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Método de solicitude",
|
||||
"request-schema-field": "Campo de esquema de solicitude",
|
||||
"request-tag-plural": "Solicitar etiquetas",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Requisitos",
|
||||
"reset": "Restablecer",
|
||||
"reset-default-layout": "Restablecer deseño predeterminado",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Rules Evaluated",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Executar",
|
||||
"run-agent-plural": "Executar Agentes",
|
||||
"run-at": "Executar ás",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Activos de datos específicos",
|
||||
"spreadsheet": "Folla de cálculo",
|
||||
"spreadsheet-plural": "Follas de cálculo",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "Función SQL",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "Consulta SQL",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "Domingo",
|
||||
"support": "Soporte",
|
||||
"support-url": "URL de soporte",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Linguas soportadas",
|
||||
"switch-persona": "Cambiar Persona",
|
||||
"sync-alert-offset": "Sincronizar alerta",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Casos de proba",
|
||||
"test-case-resolution-status": "Estado da Resolución do Caso de Proba",
|
||||
"test-case-result": "Resultados do caso de proba",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "Correo electrónico de proba",
|
||||
"test-email-connection": "Probar a conexión de correo electrónico",
|
||||
"test-entity": "Proba {{entity}}",
|
||||
"test-level-lowercase": "nivel de proba",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Probas",
|
||||
"test-plural-type": "Probas de {{type}}",
|
||||
"test-suite": "Conxunto de probas",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "Inxesta metadatos dos servizos de almacenamento máis populares.",
|
||||
"page-sub-header-for-table-profile": "Supervisa e comprende a estrutura das túas táboas co perfilador.",
|
||||
"page-sub-header-for-teams": "Representa toda a estrutura organizativa cunha xerarquía de equipos.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "Xestione os usuarios regulares na súa organización. Para administradores, visite a páxina de Administradores.",
|
||||
"paid-addon-description": "<0>{{app}}</0> é un complemento de pago para os clientes de Collate.",
|
||||
"passed-x-checks": "Pasaron {{count}} verificacións",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "Para engadir un sinónimo, simplemente escríbeo e preme Enter",
|
||||
"system-alert-edit-message": "Non está permitido editar unha alerta xerada polo sistema.",
|
||||
"system-tag-delete-disable-message": "Non está permitido eliminar etiquetas xeradas polo sistema. Podes intentar desactivar a etiqueta no seu lugar.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "Desexas proceder coa actualización das etiquetas?",
|
||||
"tailor-experience-for-persona": "¡Adapta a experiencia especificamente para o persona {{persona}}, proba!",
|
||||
"take-quick-product-tour": "Fai un tour rápido polo produto para comezar!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Asegúrese de que {{service_type}} estea configurado para permitir conexións",
|
||||
"withIp": " dende {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Proba as túas conexións antes de crear o servizo",
|
||||
"testing-your-connection-may-take-two-minutes": "A proba das túas conexións pode levar ata 2 minutos",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "Esta acción non está permitida para entidades eliminadas.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "Successfully deleted {{count}} {{entity}}s",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" xa existe. Non se permiten {{entityPlural}} duplicados.",
|
||||
"entity-already-exist-message-without-name": "Xa existe un {{entity}} cos detalles proporcionados. Non se permiten {{entityPlural}} duplicados.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "Erro ao crear {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "\"{{entity}}\" eliminado correctamente!",
|
||||
"entity-details-fetch-error": "Erro ao obter detalles de {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "Erro ao obter o número de feeds da entidade!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "Alcanzouse o límite de {{entity}}",
|
||||
"entity-removing-error": "Erro ao eliminar {{entity}}",
|
||||
"entity-unfollow-error": "Erro ao deixar de seguir {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "Erro ao actualizar {{entity}}",
|
||||
"error-selected-node-name-details": "Erro ao obter detalles de {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "Erro ao renovar o token de identificación de Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Tarefa resolta correctamente",
|
||||
"team-moved-error": "Erro ao mover o equipo",
|
||||
"test-connection-error": "Erro ao probar a conexión!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "Usuario non autorizado! Comproba o correo electrónico ou o contrasinal",
|
||||
"unexpected-error": "Produciuse un erro inesperado.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "מדדי לפרופיילר הנתונים",
|
||||
"data-proportion-plural": "יחסי נתונים",
|
||||
"data-quality": "איכות נתונים",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "בקרת איכות נתונים",
|
||||
"data-quality-test-plural": "בדיקות איכות נתונים",
|
||||
"data-quartile-plural": "רביעונים (Quaertiles)",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "הזן יחידת מדידה מותאמת אישית ולחץ Enter",
|
||||
"enter-each-value-and-press-enter": "הזן כל ערך ולחץ Enter",
|
||||
"enter-entity": "הזן {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "הזן שם {{entity}}",
|
||||
"enter-entity-value": "הזן ערך {{entity}}",
|
||||
"enter-field-description": "הזן תיאור של {{field}}",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "הדף לא נמצא",
|
||||
"page-views-by-data-asset-plural": "צפיות בדפים לפי נכסי נתונים",
|
||||
"parameter": "פרמטר",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "פרמטרים",
|
||||
"parent": "הורה",
|
||||
"parsing-timeout-limit": "מגבלת זמן לפענוח שאילתא",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Request Method",
|
||||
"request-schema-field": "Request Schema Field",
|
||||
"request-tag-plural": "בקשת תגיות",
|
||||
"required": "Required",
|
||||
"requirement-plural": "דרישות",
|
||||
"reset": "איפוס",
|
||||
"reset-default-layout": "איפוס פריסת ברירת מחדל",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "כללים שהוערכו",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "הרץ",
|
||||
"run-agent-plural": "הפעל סוכנים",
|
||||
"run-at": "הרץ ב",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "נכסי נתונים ספציפיים",
|
||||
"spreadsheet": "גיליון אלקטרוני",
|
||||
"spreadsheet-plural": "גיליונות אלקטרוניים",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "פונקציית SQL",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "שאילתת SQL",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "ראשון",
|
||||
"support": "תמיכה",
|
||||
"support-url": "כתובת תמיכה",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "שפות נתמכות",
|
||||
"switch-persona": "החלף פרסונה",
|
||||
"sync-alert-offset": "סנכרן התראה",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "בדיקות נתונים",
|
||||
"test-case-resolution-status": "סטטוס פתרון מקרי בדיקה",
|
||||
"test-case-result": "Test Case Results",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "Test Email",
|
||||
"test-email-connection": "Test Email Connection",
|
||||
"test-entity": "בדיקה {{entity}}",
|
||||
"test-level-lowercase": "רמת בדיקה",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "בדיקות",
|
||||
"test-plural-type": "בדיקות {{type}}",
|
||||
"test-suite": "מערכת בדיקות",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "שלב מטה-דאטה משירותי האחסון הפופולריים ביותר.",
|
||||
"page-sub-header-for-table-profile": "נטרו, נתחו והבינו את מבנה הטבלאות שלכם באמצועות הפרופיילר.",
|
||||
"page-sub-header-for-teams": "ייצג את מבנה הארגון באמצעות היררכיה של צוותים",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "נהל משתמשים רגילים בארגון שלך. עבור מנהלים, בקר בדף המנהלים.",
|
||||
"paid-addon-description": "<0>{{app}}</0> הוא תוסף בתשלום ללקוחות Collate.",
|
||||
"passed-x-checks": "Passed {{count}} checks",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "כדי להוסיף שם נרדף, פשוט הקלד אותו ולחץ Enter",
|
||||
"system-alert-edit-message": "עריכת התראה שנוצרה על ידי המערכת אינה מותרת.",
|
||||
"system-tag-delete-disable-message": "מחיקת תגיות שנוצרו באופן מערכתי אינה מותרת. ניתן לנסות לנטרל את התג במקום.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "האם ברצונך להמשיך בעדכון התגים?",
|
||||
"tailor-experience-for-persona": "התאם את החוויה במיוחד עבור אישיות {{persona}}, נסה את זה!",
|
||||
"take-quick-product-tour": "התחל סיור במוצר כדי להתחיל!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "אנא וודא ש‑{{service_type}} מוגדר לאפשר חיבורים",
|
||||
"withIp": " מ‑{{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "בדוק את החיבור שלך לפני שתיצור את השירות",
|
||||
"testing-your-connection-may-take-two-minutes": "בדיקת החיבור שלך עשויה לקחת עד 2 דקות",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "פעולה זו אינה מותרת עבור ישויות שנמחקו.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "{{count}} {{entity}}s נמחקו בהצלחה",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" כבר קיים. אין אפשרות ליצור {{entityPlural}} כפולים.",
|
||||
"entity-already-exist-message-without-name": "{{entity}} עם הפרטים הנתונים כבר קיים. אין אפשרות ליצור {{entityPlural}} כפולים.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "שגיאה במהלך יצירת {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "{{entity}} נמחק בהצלחה!",
|
||||
"entity-details-fetch-error": "שגיאה במהלך אחזור פרטים עבור {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "שגיאה במהלך אחזור ספירת הזרמת הפריטים!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} limit reached",
|
||||
"entity-removing-error": "שגיאה במהלך הסרת {{entity}}",
|
||||
"entity-unfollow-error": "שגיאה במהלך ביטול עקיבה אחרי {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "שגיאה במהלך עדכון {{entity}}",
|
||||
"error-selected-node-name-details": "שגיאה במהלך קבלת פרטי {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "שגיאה במהלך חידוש טוקן ID ממערכת ה-Single Sign-On של Auth0: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "המשימה נפתרה בהצלחה",
|
||||
"team-moved-error": "שגיאה במהלך העברת הקבוצה",
|
||||
"test-connection-error": "שגיאה במהלך בדיקת החיבור!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "משתמש לא מורשה! יש לבדוק את כתובת האימייל או הסיסמה",
|
||||
"unexpected-error": "אירעה שגיאה לא צפויה.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "データプロファイラメトリクス",
|
||||
"data-proportion-plural": "データ構成比",
|
||||
"data-quality": "データ品質",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "データ品質テスト",
|
||||
"data-quality-test-plural": "データ品質テスト",
|
||||
"data-quartile-plural": "データ四分位数",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "カスタム測定単位を入力してEnterを押してください",
|
||||
"enter-each-value-and-press-enter": "各値を入力してEnterキーを押してください",
|
||||
"enter-entity": "{{entity}} を入力",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "{{entity}} の名前を入力",
|
||||
"enter-entity-value": "{{entity}} の値を入力",
|
||||
"enter-field-description": "{{field}} の説明を入力",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "ページが見つかりません",
|
||||
"page-views-by-data-asset-plural": "データアセットごとのページビュー",
|
||||
"parameter": "パラメータ",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "パラメータ",
|
||||
"parent": "親",
|
||||
"parsing-timeout-limit": "クエリ解析のタイムアウト上限",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "リクエストメソッド",
|
||||
"request-schema-field": "リクエストスキーマフィールド",
|
||||
"request-tag-plural": "タグをリクエスト",
|
||||
"required": "Required",
|
||||
"requirement-plural": "要件",
|
||||
"reset": "リセット",
|
||||
"reset-default-layout": "レイアウトをデフォルトにリセット",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- ルール: {{ruleName}}",
|
||||
"rules-count": "({{count}} ルール)",
|
||||
"rules-evaluated": "評価されたルール",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "実行",
|
||||
"run-agent-plural": "エージェントを実行",
|
||||
"run-at": "実行日時",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "特定のデータアセット",
|
||||
"spreadsheet": "スプレッドシート",
|
||||
"spreadsheet-plural": "スプレッドシート",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL 関数",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL クエリ",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "日曜日",
|
||||
"support": "サポート",
|
||||
"support-url": "サポート URL",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "対応言語",
|
||||
"switch-persona": "ペルソナ切り替え",
|
||||
"sync-alert-offset": "アラートを同期",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "テストケース",
|
||||
"test-case-resolution-status": "テストケースの解決状況",
|
||||
"test-case-result": "テストケース結果",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "テストメール",
|
||||
"test-email-connection": "メール接続をテスト",
|
||||
"test-entity": "{{entity}} をテスト",
|
||||
"test-level-lowercase": "テストレベル",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "テスト",
|
||||
"test-plural-type": "{{type}}テスト",
|
||||
"test-suite": "テストスイート",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "人気のストレージサービスからメタデータを取り込みます。",
|
||||
"page-sub-header-for-table-profile": "プロファイラーでテーブル構造を監視・理解します。",
|
||||
"page-sub-header-for-teams": "階層的なチーム構造で組織全体を表現します。",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "組織の一般ユーザーを管理します。管理者については、管理者ページをご覧ください。",
|
||||
"paid-addon-description": "<0>{{app}}</0> は Collate の有料アドオンです。",
|
||||
"passed-x-checks": "Passed {{count}} checks",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "シノニムを追加するには、入力してEnterを押してください",
|
||||
"system-alert-edit-message": "システム生成アラートの編集はできません。",
|
||||
"system-tag-delete-disable-message": "システム生成タグは削除できません。代わりに無効化をお試しください。",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "タグを更新しますか?",
|
||||
"tailor-experience-for-persona": "{{persona}}向けに最適化された体験をカスタマイズしてご利用ください!",
|
||||
"take-quick-product-tour": "クイックツアーで製品を体験しましょう!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "{{service_type}} が接続を許可するように構成されていることを確認してください",
|
||||
"withIp": "{{ip}} からの接続が許可されていることを確認してください"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "サービスを作成する前に接続テストを実行してください。",
|
||||
"testing-your-connection-may-take-two-minutes": "接続テストには最大で2分かかることがあります。",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "削除されたエンティティにはこの操作を行うことができません。",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "{{count}}個の{{entity}}を正常に削除しました",
|
||||
"entity-already-exist": "{{entity}}「{{name}}」はすでに存在します。同じ{{entity}}は作成できません。",
|
||||
"entity-already-exist-message-without-name": "指定された情報で{{entity}}がすでに存在します。同じ{{entityPlural}}は作成できません。",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "{{entity}}の作成中にエラーが発生しました",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "{{entity}}の削除に成功しました!",
|
||||
"entity-details-fetch-error": "{{entityType}} {{entityName}}の詳細取得中にエラーが発生しました",
|
||||
"entity-feed-fetch-error": "エンティティのフィード件数取得中にエラーが発生しました!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}}の上限に達しました",
|
||||
"entity-removing-error": "{{entity}}の削除中にエラーが発生しました",
|
||||
"entity-unfollow-error": "{{entity}}のフォロー解除中にエラーが発生しました",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "{{entity}}の更新中にエラーが発生しました",
|
||||
"error-selected-node-name-details": "{{selectedNodeName}}の詳細取得中にエラーが発生しました",
|
||||
"error-while-renewing-id-token-with-message": "Auth0 SSOによるIDトークン更新中にエラーが発生しました:{{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "タスクが正常に解決されました",
|
||||
"team-moved-error": "チームの移動中にエラーが発生しました",
|
||||
"test-connection-error": "接続テスト中にエラーが発生しました!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "認証されていないユーザーです!メールアドレスまたはパスワードをご確認ください。",
|
||||
"unexpected-error": "予期しないエラーが発生しました。",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "데이터 프로파일러 메트릭",
|
||||
"data-proportion-plural": "데이터 비율",
|
||||
"data-quality": "데이터 품질",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "데이터 품질 테스트",
|
||||
"data-quality-test-plural": "데이터 품질 테스트들",
|
||||
"data-quartile-plural": "데이터 사분위수",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "사용자 지정 측정 단위를 입력하고 Enter를 누르세요",
|
||||
"enter-each-value-and-press-enter": "각 값을 입력하고 Enter를 누르세요",
|
||||
"enter-entity": "{{entity}} 입력",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "{{entity}} 이름 입력",
|
||||
"enter-entity-value": "{{entity}} 값 입력",
|
||||
"enter-field-description": "{{field}} 설명 입력",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "페이지를 찾을 수 없습니다",
|
||||
"page-views-by-data-asset-plural": "데이터 자산별 페이지 조회수",
|
||||
"parameter": "매개변수",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "매개변수들",
|
||||
"parent": "상위",
|
||||
"parsing-timeout-limit": "쿼리 구문 분석 시간 제한",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "요청 메서드",
|
||||
"request-schema-field": "요청 스키마 필드",
|
||||
"request-tag-plural": "태그 요청",
|
||||
"required": "Required",
|
||||
"requirement-plural": "요구사항들",
|
||||
"reset": "초기화",
|
||||
"reset-default-layout": "기본 레이아웃 초기화",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "평가된 규칙",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "실행",
|
||||
"run-agent-plural": "에이전트 실행",
|
||||
"run-at": "실행 시간",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "특정 데이터 자산들",
|
||||
"spreadsheet": "스프레드시트",
|
||||
"spreadsheet-plural": "스프레드시트",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL 함수",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL 쿼리",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "일요일",
|
||||
"support": "지원",
|
||||
"support-url": "지원 URL",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "지원되는 언어들",
|
||||
"switch-persona": "페르소나 전환",
|
||||
"sync-alert-offset": "동기화 알람",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "테스트 케이스들",
|
||||
"test-case-resolution-status": "테스트 케이스 해결 상태",
|
||||
"test-case-result": "테스트 케이스 결과",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "이메일 테스트",
|
||||
"test-email-connection": "이메일 연결 테스트",
|
||||
"test-entity": "{{entity}} 테스트",
|
||||
"test-level-lowercase": "테스트 레벨",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "테스트들",
|
||||
"test-plural-type": "{{type}} 테스트",
|
||||
"test-suite": "테스트 스위트",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "가장 인기 있는 저장소 서비스에서 메타데이터를 수집하세요.",
|
||||
"page-sub-header-for-table-profile": "프로파일러를 사용하여 테이블 구조를 모니터링하고 이해하세요.",
|
||||
"page-sub-header-for-teams": "계층적 팀으로 전체 조직 구조를 표현하세요.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "계층적 팀으로 전체 조직 구조를 표현하세요.",
|
||||
"paid-addon-description": "<0>{{app}}</0>은(는) Collate 고객을 위한 유료 애드온입니다.",
|
||||
"passed-x-checks": "{{count}}개 검사 통과",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "동의어를 추가하려면 입력하고 Enter 키를 누르세요",
|
||||
"system-alert-edit-message": "시스템에서 생성된 알림은 편집할 수 없습니다.",
|
||||
"system-tag-delete-disable-message": "시스템에서 생성된 태그를 삭제하는 것은 허용되지 않습니다. 대신 태그를 비활성화할 수 있습니다.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "새 태그를 추가하시겠습니까?",
|
||||
"tailor-experience-for-persona": "{{persona}} 페르소나에 맞게 경험을 맞춤 설정하고 시도해보세요!",
|
||||
"take-quick-product-tour": "시작하려면 제품 투어를 진행하세요!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "{{service_type}} 가 연결을 허용하도록 구성되어 있는지 확인하세요",
|
||||
"withIp": " {{ip}} 에서"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "서비스를 생성하기 전에 연결을 테스트하세요",
|
||||
"testing-your-connection-may-take-two-minutes": "연결 테스트는 최대 2분이 소요될 수 있습니다",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "이 작업은 삭제된 엔티티에 대해 허용되지 않습니다.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "{{count}}개의 {{entity}} 삭제 성공",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\"이(가) 이미 존재합니다. 중복된 {{entityPlural}}은(는) 허용되지 않습니다.",
|
||||
"entity-already-exist-message-without-name": "주어진 세부 정보를 가진 {{entity}}가 이미 존재합니다. 중복된 {{entityPlural}}은(는) 허용되지 않습니다.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "{{entity}} 생성 중 오류가 발생했습니다",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "\"{{entity}}\"이(가) 성공적으로 삭제되었습니다!",
|
||||
"entity-details-fetch-error": "{{entityType}} {{entityName}}의 세부 정보를 가져오는 중 오류가 발생했습니다",
|
||||
"entity-feed-fetch-error": "엔티티 피드 수를 가져오는 중 오류가 발생했습니다!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} 한도에 도달했습니다",
|
||||
"entity-removing-error": "{{entity}} 제거 중 오류가 발생했습니다",
|
||||
"entity-unfollow-error": "{{entity}} 언팔로우 중 오류가 발생했습니다",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "{{entity}} 업데이트 중 오류가 발생했습니다",
|
||||
"error-selected-node-name-details": "{{selectedNodeName}} 세부 정보를 가져오는 중 오류가 발생했습니다",
|
||||
"error-while-renewing-id-token-with-message": "Auth0 SSO에서 ID 토큰 갱신 중 오류 발생: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "작업이 성공적으로 해결되었습니다",
|
||||
"team-moved-error": "팀 이동 중 오류가 발생했습니다",
|
||||
"test-connection-error": "연결 테스트 중 오류가 발생했습니다!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "인증되지 않은 사용자입니다! 이메일 또는 비밀번호를 확인해주세요",
|
||||
"unexpected-error": "예기치 않은 오류가 발생했습니다.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "डेटा प्रोफाइलर मेट्रिक्स",
|
||||
"data-proportion-plural": "डेटा प्रमाण",
|
||||
"data-quality": "डेटा गुणवत्ता",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "डेटा गुणवत्ता चाचणी",
|
||||
"data-quality-test-plural": "डेटा गुणवत्ता परीक्षा",
|
||||
"data-quartile-plural": "डेटा चतुर्थांश",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "कस्टम मापन एकक प्रविष्ट करा आणि Enter दाबा",
|
||||
"enter-each-value-and-press-enter": "Enter each value and press Enter",
|
||||
"enter-entity": "{{entity}} प्रविष्ट करा",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "{{entity}} नाव प्रविष्ट करा",
|
||||
"enter-entity-value": "{{entity}} मूल्य प्रविष्ट करा",
|
||||
"enter-field-description": "{{field}} वर्णन प्रविष्ट करा",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "पृष्ठ सापडले नाही",
|
||||
"page-views-by-data-asset-plural": "डेटा ॲसेट्सने पृष्ठ दृश्ये",
|
||||
"parameter": "पॅरामीटर",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "पॅरामीटर्स",
|
||||
"parent": "पालक",
|
||||
"parsing-timeout-limit": "क्वेरी पार्सिंग टाइमआउट मर्यादा",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "विनंती पद्धत",
|
||||
"request-schema-field": "विनंती स्कीमा फील्ड",
|
||||
"request-tag-plural": "विनंती टॅग",
|
||||
"required": "Required",
|
||||
"requirement-plural": "आवश्यकता",
|
||||
"reset": "रीसेट",
|
||||
"reset-default-layout": "मूलभूत लेआउट रीसेट करा",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Rules Evaluated",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "चालवा",
|
||||
"run-agent-plural": "एजेंट्स चलवा",
|
||||
"run-at": "येथे चालवा",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "विशिष्ट डेटा ॲसेट",
|
||||
"spreadsheet": "स्प्रेडशीट",
|
||||
"spreadsheet-plural": "स्प्रेडशीट्स",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL फंक्शन",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL क्वेरी",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "रविवार",
|
||||
"support": "समर्थन",
|
||||
"support-url": "समर्थन URL",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "समर्थित भाषा",
|
||||
"switch-persona": "व्यक्तिमत्त्व बदला",
|
||||
"sync-alert-offset": "सूचना समक्रमित करा",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "चाचणी प्रकरणे",
|
||||
"test-case-resolution-status": "टेस्ट केस स्थिती सुलभीकरण",
|
||||
"test-case-result": "चाचणी प्रकरण परिणाम",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "चाचणी ईमेल",
|
||||
"test-email-connection": "चाचणी ईमेल कनेक्शन",
|
||||
"test-entity": "चाचणी {{entity}}",
|
||||
"test-level-lowercase": "चाचणी पातळी",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "चाचण्या",
|
||||
"test-plural-type": "{{type}} चाचण्या",
|
||||
"test-suite": "चाचणी संच",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "सर्वात लोकप्रिय स्टोरेज सेवांमधून मेटाडेटा अंतर्ग्रहण करा.",
|
||||
"page-sub-header-for-table-profile": "प्रोफाइलरसह तुमच्या तक्त्यांची रचना मॉनिटर आणि समजून घ्या",
|
||||
"page-sub-header-for-teams": "सांकेतिक टीम्ससह तुमची संपूर्ण संस्थात्मक रचना दर्शवा.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "आपल्या संस्थेतील नियमित वापरकर्त्यांचे व्यवस्थापन करा. प्रशासकांसाठी, प्रशासक पृष्ठास भेट द्या.",
|
||||
"paid-addon-description": "<0>{{app}}</0> हे Collate ग्राहकांसाठी एक सशुल्क अॅड-ऑन आहे.",
|
||||
"passed-x-checks": "{{count}} तपासण्या उत्तीर्ण",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "समानार्थी शब्द जोडण्यासाठी, फक्त टाइप करा आणि Enter दाबा",
|
||||
"system-alert-edit-message": "सिस्टम व्युत्पन्न अलर्ट संपादित करण्याची परवानगी नाही.",
|
||||
"system-tag-delete-disable-message": "सिस्टम व्युत्पन्न टॅग्स हटविण्याची परवानगी नाही. त्याऐवजी तुम्ही टॅग अक्षम करण्याचा प्रयत्न करू शकता.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "नवीन टॅग जोडण्यासाठी तुम्हाला पुढे जायचे आहे का?",
|
||||
"tailor-experience-for-persona": "{{persona}} पर्सोनासाठी अनुभव अनुकूलित करा, प्रयत्न करा!",
|
||||
"take-quick-product-tour": "प्रारंभ करण्यासाठी एक उत्पादन टूर घ्या!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "कृपया खात्री करा की {{service_type}} कनेक्शनसाठी कॉन्फिगर केले गेले आहे",
|
||||
"withIp": " {{ip}} वरून"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "सेवा तयार करण्यापूर्वी तुमचे कनेक्शन चाचणी करा",
|
||||
"testing-your-connection-may-take-two-minutes": "तुमचे कनेक्शन चाचणी करण्यास 2 मिनिटे लागू शकतात",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "मिटवलेल्या घटकांसाठी ही क्रिया अनुमत नाही.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "Successfully deleted {{count}} {{entity}}s",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" आधीच अस्तित्वात आहे. डुप्लिकेट {{entityPlural}} अनुमत नाहीत.",
|
||||
"entity-already-exist-message-without-name": "दिलेल्या तपशीलांसह {{entity}} आधीच अस्तित्वात आहे. डुप्लिकेट {{entityPlural}} अनुमत नाहीत.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "{{entity}} तयार करताना त्रुटी",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "\"{{entity}}\" यशस्वीरित्या मिटवले!",
|
||||
"entity-details-fetch-error": "{{entityType}} {{entityName}} साठी तपशील मिळवताना त्रुटी",
|
||||
"entity-feed-fetch-error": "घटक फीड गणना मिळवताना त्रुटी!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} मर्यादा गाठली",
|
||||
"entity-removing-error": "{{entity}} काढताना त्रुटी",
|
||||
"entity-unfollow-error": "{{entity}} अनफॉलो करताना त्रुटी",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "{{entity}} अद्यतनित करताना त्रुटी",
|
||||
"error-selected-node-name-details": "{{selectedNodeName}} तपशील मिळवताना त्रुटी",
|
||||
"error-while-renewing-id-token-with-message": "Auth0 SSO मधून id टोकन नूतनीकरण करताना त्रुटी: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "कार्य यशस्वीरित्या सोडवले",
|
||||
"team-moved-error": "टीम हलवताना त्रुटी",
|
||||
"test-connection-error": "कनेक्शन चाचणी करताना त्रुटी!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "अनधिकृत वापरकर्ता! कृपया ईमेल किंवा पासवर्ड तपासा",
|
||||
"unexpected-error": "अप्रत्याशित त्रुटी आली.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Dataprofilemetrieken",
|
||||
"data-proportion-plural": "Dataproporties",
|
||||
"data-quality": "Datakwaliteit",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Datakwaliteitstest",
|
||||
"data-quality-test-plural": "Data Qualiteits Tests",
|
||||
"data-quartile-plural": "Datakwartielen",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Voer een aangepaste maateenheid in en druk op Enter",
|
||||
"enter-each-value-and-press-enter": "Voer elke waarde in en druk op Enter",
|
||||
"enter-entity": "{{entity}} invoeren",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "{{entity}}-naam invoeren",
|
||||
"enter-entity-value": "{{entity}}-waarde invoeren",
|
||||
"enter-field-description": "{{field}}-beschrijving invoeren",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Pagina niet gevonden",
|
||||
"page-views-by-data-asset-plural": "Paginaweergaven per data-asset",
|
||||
"parameter": "Parameter",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Parameters",
|
||||
"parent": "Ouder",
|
||||
"parsing-timeout-limit": "Time-outlimiet voor query-analyse",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Request Method",
|
||||
"request-schema-field": "Request Schema Field",
|
||||
"request-tag-plural": "Aanvraagtags",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Vereisten",
|
||||
"reset": "Herstellen",
|
||||
"reset-default-layout": "Standaardindeling herstellen",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Regels geëvalueerd",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Uitvoeren",
|
||||
"run-agent-plural": "Agents Uitvoeren",
|
||||
"run-at": "Uitvoeren op",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Specifieke data-assets",
|
||||
"spreadsheet": "Spreadsheet",
|
||||
"spreadsheet-plural": "Spreadsheets",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL-functie",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL-Query",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "zondag",
|
||||
"support": "Ondersteuning",
|
||||
"support-url": "Ondersteunings-URL",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Ondersteunde talen",
|
||||
"switch-persona": "Persona wisselen",
|
||||
"sync-alert-offset": "Waarschuwing synchroniseren",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Testcases",
|
||||
"test-case-resolution-status": "Test Case Resolution Status",
|
||||
"test-case-result": "Testcaseresultaten",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "Test E-mail",
|
||||
"test-email-connection": "Test emailconnectie",
|
||||
"test-entity": "Test {{entity}}",
|
||||
"test-level-lowercase": "testniveau",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Tests",
|
||||
"test-plural-type": "{{type}}-testen",
|
||||
"test-suite": "Testsuite",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "Ingest metadata van de meestgebruikte opslagservices.",
|
||||
"page-sub-header-for-table-profile": "Volg en begrijp de structuur van je tabellen met de profiler.",
|
||||
"page-sub-header-for-teams": "Vertegenwoordig je hele organisatiestructuur met hiërarchische teams.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "Beheer reguliere gebruikers in uw organisatie. Voor beheerders, bezoek de Beheerders pagina.",
|
||||
"paid-addon-description": "<0>{{app}}</0> is een betaalde add-on voor Collate-klanten.",
|
||||
"passed-x-checks": "{{count}} controles geslaagd",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "Voeg een synoniem toe door het gewoon in te typen en op Enter te drukken",
|
||||
"system-alert-edit-message": "Het bewerken van een door het systeem gegenereerde alert is niet toegestaan.",
|
||||
"system-tag-delete-disable-message": "Het verwijderen van door het systeem gegenereerde tags is niet toegestaan. Je kunt proberen de tag uit te schakelen.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "Wilt u doorgaan met het bijwerken van de tags?",
|
||||
"tailor-experience-for-persona": "Pas de ervaring specifiek aan voor de {{persona}} persona, probeer het eens!",
|
||||
"take-quick-product-tour": "Maak een producttour om aan de slag te gaan!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Zorg ervoor dat {{service_type}} is geconfigureerd om verbindingen toe te staan",
|
||||
"withIp": " vanaf {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Test je connecties voordat je de service maakt",
|
||||
"testing-your-connection-may-take-two-minutes": "Het testen van je connecties kan tot 2 minuten duren",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "Deze actie is niet toegestaan voor verwijderde entiteiten.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "{{count}} {{entity}}s succesvol verwijderd",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" bestaat al. Gedupliceerde {{entityPlural}} zijn niet toegestaan.",
|
||||
"entity-already-exist-message-without-name": "Een {{entity}} met de opgegeven data bestaat al. Gedupliceerde {{entityPlural}} zijn niet toegestaan.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "Fout bij het maken van {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "{{entity}} succesvol verwijderd!",
|
||||
"entity-details-fetch-error": "Fout bij het ophalen van details voor {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "Fout bij het ophalen van feedtelling voor entiteit!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} limit reached",
|
||||
"entity-removing-error": "Fout bij het verwijderen van {{entity}}",
|
||||
"entity-unfollow-error": "Fout bij het ontvolgen van {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "Fout bij het updaten van {{entity}}",
|
||||
"error-selected-node-name-details": "Fout bij het ophalen van details voor {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "Fout bij het vernieuwen van id-token vanuit Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Taak succesvol opgelost",
|
||||
"team-moved-error": "Fout bij het verplaatsen van team",
|
||||
"test-connection-error": "Fout bij het testen van de connectie!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "Ongeautoriseerde gebruiker! controleer e-mail of wachtwoord",
|
||||
"unexpected-error": "Er is een onverwachte fout opgetreden.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "شاخصهای پروفایل داده",
|
||||
"data-proportion-plural": "نسبتهای داده",
|
||||
"data-quality": "کیفیت داده",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "آزمون کیفیت داده",
|
||||
"data-quality-test-plural": "Pruebas de Calidad de Datos",
|
||||
"data-quartile-plural": "چهارکهای داده",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "واحد اندازهگیری سفارشی را وارد کرده و Enter را بزنید",
|
||||
"enter-each-value-and-press-enter": "Enter each value and press Enter",
|
||||
"enter-entity": "ورود {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "نام {{entity}} را وارد کنید",
|
||||
"enter-entity-value": "مقدار {{entity}} را وارد کنید",
|
||||
"enter-field-description": "توضیحات {{field}} را وارد کنید",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "صفحه یافت نشد",
|
||||
"page-views-by-data-asset-plural": "بازدیدهای صفحه توسط داراییهای داده",
|
||||
"parameter": "پارامتر",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "پارامترها",
|
||||
"parent": "والد",
|
||||
"parsing-timeout-limit": "محدودیت زمان برای تجزیه پرس و جو",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "روش درخواست",
|
||||
"request-schema-field": "فیلد اسکیما درخواست",
|
||||
"request-tag-plural": "برچسبهای درخواست",
|
||||
"required": "Required",
|
||||
"requirement-plural": "نیازمندیها",
|
||||
"reset": "بازنشانی",
|
||||
"reset-default-layout": "بازنشانی طرحبندی پیشفرض",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Rules Evaluated",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "اجرا",
|
||||
"run-agent-plural": "اجرای عاملها",
|
||||
"run-at": "اجرا در",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "داراییهای داده خاص",
|
||||
"spreadsheet": "صفحه گسترده",
|
||||
"spreadsheet-plural": "صفحات گسترده",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "تابع SQL",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "پرس و جوی SQL",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "یکشنبه",
|
||||
"support": "پشتیبانی",
|
||||
"support-url": "آدرس پشتیبانی",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "زبانهای پشتیبانیشده",
|
||||
"switch-persona": "تغییر شخصیت",
|
||||
"sync-alert-offset": "همگامسازی هشدار",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "موردهای تست",
|
||||
"test-case-resolution-status": "وضعیت حل موارد آزمون",
|
||||
"test-case-result": "نتایج مورد تست",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "ایمیل تست",
|
||||
"test-email-connection": "تست اتصال ایمیل",
|
||||
"test-entity": "تست {{entity}}",
|
||||
"test-level-lowercase": "سطح تست",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "تستها",
|
||||
"test-plural-type": "Testy {{type}}",
|
||||
"test-suite": "مجموعه تست",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "ورود متادیتا از پرکاربردترین سرویسهای ذخیرهسازی.",
|
||||
"page-sub-header-for-table-profile": "نظارت و درک ساختار جداول خود با استفاده از پروفایلر.",
|
||||
"page-sub-header-for-teams": "نمایش ساختار کامل سازمانی خود با تیمهای سلسلهمراتبی.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "کاربران عادی سازمان خود را مدیریت کنید. برای مدیران، به صفحه مدیران مراجعه کنید.",
|
||||
"paid-addon-description": "<0>{{app}}</0> افزونه پولی برای مشتریان Collate است.",
|
||||
"passed-x-checks": "{{count}} بررسی موفق",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "برای افزودن یک مترادف، آن را تایپ کنید و Enter را فشار دهید.",
|
||||
"system-alert-edit-message": "ویرایش هشدار تولید شده توسط سیستم مجاز نیست.",
|
||||
"system-tag-delete-disable-message": "حذف برچسبهای تولید شده توسط سیستم مجاز نیست. میتوانید برچسب را غیرفعال کنید.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "آیا میخواهید بهروزرسانی برچسبها را ادامه دهید؟",
|
||||
"tailor-experience-for-persona": "Tailor the experience specifically for the {{persona}} persona, just give it a spin!",
|
||||
"take-quick-product-tour": "یک تور محصولی برای شروع بگذارید!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "لطفاً اطمینان حاصل کنید که {{service_type}} به درستی برای اجازه اتصال پیکربندی شده است",
|
||||
"withIp": " از {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "اتصالات خود را قبل از ایجاد سرویس تست کنید.",
|
||||
"testing-your-connection-may-take-two-minutes": "تست اتصالات شما ممکن است تا ۲ دقیقه طول بکشد.",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "این اقدام برای موجودیتهای حذف شده مجاز نیست.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "Successfully deleted {{count}} {{entity}}s",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" قبلاً وجود دارد. موجودیتهای تکراری مجاز نیستند.",
|
||||
"entity-already-exist-message-without-name": "یک {{entity}} با جزئیات داده شده قبلاً وجود دارد. موجودیتهای تکراری مجاز نیستند.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "خطا در ایجاد {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "\"{{entity}}\" با موفقیت حذف شد!",
|
||||
"entity-details-fetch-error": "خطا در بازیابی جزئیات برای {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "خطا در بازیابی تعداد فید موجودیت!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "محدودیت {{entity}} رسید.",
|
||||
"entity-removing-error": "خطا در حذف {{entity}}",
|
||||
"entity-unfollow-error": "خطا در لغو دنبال کردن {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "خطا در بهروزرسانی {{entity}}",
|
||||
"error-selected-node-name-details": "خطا در دریافت جزئیات {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "خطا در تجدید توکن id از Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "وظیفه با موفقیت حل شد.",
|
||||
"team-moved-error": "خطا در انتقال تیم.",
|
||||
"test-connection-error": "خطا در تست اتصال!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "کاربر غیرمجاز! لطفاً ایمیل یا رمز عبور را بررسی کنید.",
|
||||
"unexpected-error": "یک خطای غیرمنتظره رخ داده است.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Métricas do Examinador de Dados",
|
||||
"data-proportion-plural": "Proporções de Dados",
|
||||
"data-quality": "Qualidade de Dados",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Teste de Qualidade de Dados",
|
||||
"data-quality-test-plural": "Total de testes",
|
||||
"data-quartile-plural": "Quartis de Dados",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Digite a unidade de medida personalizada e pressione Enter",
|
||||
"enter-each-value-and-press-enter": "Digite cada valor e pressione Enter",
|
||||
"enter-entity": "Inserir {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "Inserir nome de {{entity}}",
|
||||
"enter-entity-value": "Inserir Valor de {{entity}}",
|
||||
"enter-field-description": "Inserir descrição de {{field}}",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Página Não Encontrada",
|
||||
"page-views-by-data-asset-plural": "Visualizações de Página por Ativos de Dados",
|
||||
"parameter": "Parâmetro",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Parâmetros",
|
||||
"parent": "Pai",
|
||||
"parsing-timeout-limit": "Limite de Tempo de Análise de Consulta",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Método de solicitação",
|
||||
"request-schema-field": "Campo de esquema da requisição",
|
||||
"request-tag-plural": "Solicitar Tags",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Requisitos",
|
||||
"reset": "Redefinir",
|
||||
"reset-default-layout": "Redefinir Layout Padrão",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Regras avaliadas",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Executar",
|
||||
"run-agent-plural": "Executar Agentes",
|
||||
"run-at": "Executar em",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Ativos de Dados Específicos",
|
||||
"spreadsheet": "Planilha",
|
||||
"spreadsheet-plural": "Planilhas",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "Função SQL",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "Consulta SQL",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "Domingo",
|
||||
"support": "Suporte",
|
||||
"support-url": "URL de Suporte",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Idiomas Suportados",
|
||||
"switch-persona": "Trocar Persona",
|
||||
"sync-alert-offset": "Sincronizar alerta",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Casos de Teste",
|
||||
"test-case-resolution-status": "Status de Resolução do Caso de Teste",
|
||||
"test-case-result": "Resultados do Caso de Teste",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "E-mail de Teste",
|
||||
"test-email-connection": "Testar conexão de e-mail",
|
||||
"test-entity": "Teste {{entity}}",
|
||||
"test-level-lowercase": "nível de teste",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Testes",
|
||||
"test-plural-type": "Testes de {{type}}",
|
||||
"test-suite": "Conjunto de Testes",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "Ingestão de metadados dos serviços de armazenamento mais populares.",
|
||||
"page-sub-header-for-table-profile": "Monitore e compreenda a estrutura de suas tabelas com o examinador.",
|
||||
"page-sub-header-for-teams": "Represente toda a estrutura organizacional com equipes hierárquicas.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "Gerencie os usuários regulares em sua organização. Para administradores, visite a página de Administradores.",
|
||||
"paid-addon-description": "<0>{{app}}</0> é um complemento pago para clientes do Collate.",
|
||||
"passed-x-checks": "{{count}} verificações aprovadas",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "Para adicionar um sinônimo, basta digitá-lo e pressionar Enter",
|
||||
"system-alert-edit-message": "Não é permitido editar um alerta gerado pelo sistema.",
|
||||
"system-tag-delete-disable-message": "Não é permitido excluir tags geradas pelo sistema. Você pode tentar desativar a tag em vez disso.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "Você gostaria de continuar com a atualização das tags?",
|
||||
"tailor-experience-for-persona": "Adapte a experiência especificamente para o persona {{persona}}, experimente!",
|
||||
"take-quick-product-tour": "Faça um tour pelo produto para começar!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Por favor, certifique‑se de que o {{service_type}} está configurado para permitir conexões",
|
||||
"withIp": " de {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Teste suas conexões antes de criar o serviço",
|
||||
"testing-your-connection-may-take-two-minutes": "Testar suas conexões pode levar até 2 minutos",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "Esta ação não é permitida para entidades excluídas.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "{{count}} {{entity}}s excluídos com sucesso",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" já existe. {{entityPlural}} duplicados não são permitidos.",
|
||||
"entity-already-exist-message-without-name": "Um {{entity}} com os detalhes fornecidos já existe. {{entityPlural}} duplicados não são permitidos.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "Erro ao criar {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "{{entity}} excluído com sucesso!",
|
||||
"entity-details-fetch-error": "Erro ao buscar detalhes para {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "Erro ao buscar contagem de feed de entidade!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} limite atingido",
|
||||
"entity-removing-error": "Erro ao remover {{entity}}",
|
||||
"entity-unfollow-error": "Erro ao deixar de seguir {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "Erro ao atualizar {{entity}}",
|
||||
"error-selected-node-name-details": "Erro ao obter detalhes de {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "Erro ao renovar o token de identificação do Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Tarefa resolvida com sucesso",
|
||||
"team-moved-error": "Erro ao mover a equipe",
|
||||
"test-connection-error": "Erro ao testar a conexão!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "Usuário não autorizado! Por favor, verifique o e-mail ou a senha",
|
||||
"unexpected-error": "Ocorreu um erro inesperado.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Métricas do Examinador de Dados",
|
||||
"data-proportion-plural": "Proporções de Dados",
|
||||
"data-quality": "Qualidade de Dados",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Teste de Qualidade de Dados",
|
||||
"data-quality-test-plural": "Testes de Qualidade de Dados",
|
||||
"data-quartile-plural": "Quartis de Dados",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Digite a unidade de medida personalizada e prima Enter",
|
||||
"enter-each-value-and-press-enter": "Introduza cada valor e prima Enter",
|
||||
"enter-entity": "Inserir {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "Inserir nome de {{entity}}",
|
||||
"enter-entity-value": "Inserir Valor de {{entity}}",
|
||||
"enter-field-description": "Inserir descrição de {{field}}",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Página Não Encontrada",
|
||||
"page-views-by-data-asset-plural": "Visualizações de Página por Ativos de Dados",
|
||||
"parameter": "Parâmetro",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Parâmetros",
|
||||
"parent": "Pai",
|
||||
"parsing-timeout-limit": "Limite de Tempo de Análise de Consulta",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Request Method",
|
||||
"request-schema-field": "Request Schema Field",
|
||||
"request-tag-plural": "Solicitar Etiquetas",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Requisitos",
|
||||
"reset": "Redefinir",
|
||||
"reset-default-layout": "Redefinir Layout Padrão",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Regras avaliadas",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Executar",
|
||||
"run-agent-plural": "Executar Agentes",
|
||||
"run-at": "Executar em",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Ativos de Dados Específicos",
|
||||
"spreadsheet": "Folha de cálculo",
|
||||
"spreadsheet-plural": "Folhas de cálculo",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "Função SQL",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "Consulta SQL",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "Domingo",
|
||||
"support": "Suporte",
|
||||
"support-url": "URL de Suporte",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Idiomas Suportados",
|
||||
"switch-persona": "Trocar Persona",
|
||||
"sync-alert-offset": "Sync Alert",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Casos de Teste",
|
||||
"test-case-resolution-status": "Estado da Resolução do Caso de Teste",
|
||||
"test-case-result": "Resultados do Caso de Teste",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "E-mail de Teste",
|
||||
"test-email-connection": "Test Email Connection",
|
||||
"test-entity": "Teste {{entity}}",
|
||||
"test-level-lowercase": "nível de teste",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Testes",
|
||||
"test-plural-type": "Testes de {{type}}",
|
||||
"test-suite": "Conjunto de Testes",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "Ingestão de metadados dos serviços de armazenamento mais populares.",
|
||||
"page-sub-header-for-table-profile": "Monitorize e compreenda a estrutura de suas tabelas com o examinador.",
|
||||
"page-sub-header-for-teams": "Represente toda a estrutura organizacional com equipas hierárquicas.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "Veja e gerencie os utilizadores regulares em sua organização. Para utilizadores administradores, visite a página de Administradores.",
|
||||
"paid-addon-description": "<0>{{app}}</0> é um complemento pago para clientes Collate.",
|
||||
"passed-x-checks": "{{count}} verificações aprovadas",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "Para adicionar um sinónimo, basta digitá-lo e pressionar Enter",
|
||||
"system-alert-edit-message": "Editing a system generated alert is not allowed.",
|
||||
"system-tag-delete-disable-message": "Não é permitido excluir tags geradas pelo sistema. Você pode tentar desativar a tag em vez disso.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "Would you like to proceed with updating the tags?",
|
||||
"tailor-experience-for-persona": "Adapte a experiência especificamente para o persona {{persona}}, experimente!",
|
||||
"take-quick-product-tour": "Faça um tour pelo produto para começar!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Por favor, assegure-se de que o {{service_type}} está configurado para permitir ligações",
|
||||
"withIp": " a partir de {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Teste suas conexões antes de criar o serviço",
|
||||
"testing-your-connection-may-take-two-minutes": "Testar suas conexões pode levar até 2 minutos",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "Esta ação não é permitida para entidades excluídas.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "Successfully deleted {{count}} {{entity}}s",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" já existe. {{entityPlural}} duplicados não são permitidos.",
|
||||
"entity-already-exist-message-without-name": "Um {{entity}} com os detalhes fornecidos já existe. {{entityPlural}} duplicados não são permitidos.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "Erro ao criar {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "{{entity}} excluído com sucesso!",
|
||||
"entity-details-fetch-error": "Erro ao buscar detalhes para {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "Erro ao buscar contagem de feed de entidade!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} limit reached",
|
||||
"entity-removing-error": "Erro ao remover {{entity}}",
|
||||
"entity-unfollow-error": "Erro ao deixar de seguir {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "Erro ao atualizar {{entity}}",
|
||||
"error-selected-node-name-details": "Erro ao obter detalhes de {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "Erro ao renovar o token de identificação do Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Tarefa resolvida com sucesso",
|
||||
"team-moved-error": "Erro ao mover a equipa",
|
||||
"test-connection-error": "Erro ao testar a conexão!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "Utilizador não autorizado! Por favor, verifique o e-mail ou a senha",
|
||||
"unexpected-error": "Ocorreu um erro inesperado.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Метрики профилирования данных",
|
||||
"data-proportion-plural": "Распределение данных",
|
||||
"data-quality": "Качество данных",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Тест качества данных",
|
||||
"data-quality-test-plural": "Тесты качества данных",
|
||||
"data-quartile-plural": "Качество данных",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Введите пользовательскую единицу измерения и нажмите Enter",
|
||||
"enter-each-value-and-press-enter": "Введите каждое значение и нажмите Enter",
|
||||
"enter-entity": "Введите объект «{{entity}}»",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "Введите имя объекта «{{entity}}»",
|
||||
"enter-entity-value": "Введите значение объекта «{{entity}}»",
|
||||
"enter-field-description": "Введите описание {{field}}",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Страница не найдена",
|
||||
"page-views-by-data-asset-plural": "Просмотры объектов данных",
|
||||
"parameter": "Параметр",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Параметры",
|
||||
"parent": "Родитель",
|
||||
"parsing-timeout-limit": "Ограничение по времени парсинга запроса",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Метод запроса",
|
||||
"request-schema-field": "Поле схемы запроса",
|
||||
"request-tag-plural": "Предложить тег",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Требования",
|
||||
"reset": "Сбросить",
|
||||
"reset-default-layout": "Сбросить стандартный макет",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Правило: {{ruleName}}",
|
||||
"rules-count": "({{count}} правил)",
|
||||
"rules-evaluated": "Правила оценены",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Запустить",
|
||||
"run-agent-plural": "Запустить агенты",
|
||||
"run-at": "Запустить в ",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Специфические объекты данных",
|
||||
"spreadsheet": "Электронная таблица",
|
||||
"spreadsheet-plural": "Электронные таблицы",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL-функция",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL-запрос",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "Воскресенье",
|
||||
"support": "Поддержка",
|
||||
"support-url": "URL поддержки",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Поддерживаемые языки",
|
||||
"switch-persona": "Переключить Персону",
|
||||
"sync-alert-offset": "Синхронизировать оповещение",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Проверки",
|
||||
"test-case-resolution-status": "Статус решения тестового случая",
|
||||
"test-case-result": "Результат проверки",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "Протестировать электронную почту",
|
||||
"test-email-connection": "Протестировать подключение электронной почты",
|
||||
"test-entity": "Проверка объекта «{{entity}}»",
|
||||
"test-level-lowercase": "уровень теста",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Проверки",
|
||||
"test-plural-type": "Тесты {{type}}",
|
||||
"test-suite": "Тестирование",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "Получайте метаданные из самых популярных служб хранения.",
|
||||
"page-sub-header-for-table-profile": "Отслеживайте и анализируйте структуру ваших таблиц с помощью профилировщика.",
|
||||
"page-sub-header-for-teams": "Представьте организационную структуру в виде команд.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "Управляйте пользователями.",
|
||||
"paid-addon-description": "<0>{{app}}</0> платное дополнение для пользователей Collate",
|
||||
"passed-x-checks": "Пройдено {{count}} проверок",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "Введите синоним и нажмите Enter.",
|
||||
"system-alert-edit-message": "Редактирование системного оповещения запрещено.",
|
||||
"system-tag-delete-disable-message": "Нельзя удалить системный тег. Отключите его, если он не нужен",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "Продолжить добавление нового тега?",
|
||||
"tailor-experience-for-persona": "Настройте опыт специально для персонажа {{persona}}, попробуйте!",
|
||||
"take-quick-product-tour": "Ознакомьтесь с продуктом, чтобы начать работу!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Пожалуйста, убедитесь, что {{service_type}} настроен на разрешение подключений",
|
||||
"withIp": " с {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Проверьте свои подключения перед созданием сервиса",
|
||||
"testing-your-connection-may-take-two-minutes": "Проверка подключений может занять до 2 минут.",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "Это действие невозможно для удаленных объектов.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "Успешно удалено {{count}} объектов «{{entity}}»",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" уже существует.",
|
||||
"entity-already-exist-message-without-name": "{{entity}} с указанными данными уже существует.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "Ошибка при создании объекта «{{entity}}»!",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "Объект «{{entity}}» удален!",
|
||||
"entity-details-fetch-error": "Ошибка при получении сведений для объекта «{{entityType}}» {{entityName}}",
|
||||
"entity-feed-fetch-error": "Ошибка получения событий ленты!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "Достигнут лимит объекта «{{entity}}»",
|
||||
"entity-removing-error": "Ошибка при удалении объекта «{{entity}}».",
|
||||
"entity-unfollow-error": "Ошибка при отмене подписки на объект «{{entity}}»",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "Ошибка при обновлении объекта «{{entity}}»",
|
||||
"error-selected-node-name-details": "Ошибка при получении сведений о {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "Ошибка при обновлении токена идентификатора из системы единого входа Auth0: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Задача решена",
|
||||
"team-moved-error": "Ошибка при перемещении команды",
|
||||
"test-connection-error": "Ошибка при проверке соединения!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "Это действие нельзя отменить.",
|
||||
"unauthorized-user": "Неавторизованный пользователь! пожалуйста, проверьте электронную почту или пароль",
|
||||
"unexpected-error": "Произошла непредвиденная ошибка.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "เมตริกโปรไฟล์ข้อมูล",
|
||||
"data-proportion-plural": "สัดส่วนข้อมูล",
|
||||
"data-quality": "คุณภาพข้อมูล",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "การทดสอบคุณภาพข้อมูล",
|
||||
"data-quality-test-plural": "การทดสอบคุณภาพของข้อมูล",
|
||||
"data-quartile-plural": "ควอไทล์ข้อมูล",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "กรอกหน่วยวัดที่กำหนดเองและกด Enter",
|
||||
"enter-each-value-and-press-enter": "ป้อนค่าแต่ละค่าแล้วกด Enter",
|
||||
"enter-entity": "ป้อน {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "ป้อนชื่อ {{entity}}",
|
||||
"enter-entity-value": "ป้อนค่าของ {{entity}}",
|
||||
"enter-field-description": "ป้อนคำอธิบาย {{field}}",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "ไม่พบหน้า",
|
||||
"page-views-by-data-asset-plural": "จำนวนการเข้าชมหน้าโดยสินทรัพย์ข้อมูล",
|
||||
"parameter": "พารามิเตอร์",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "พารามิเตอร์หลายรายการ",
|
||||
"parent": "ผู้ปกครอง",
|
||||
"parsing-timeout-limit": "ขีดจำกัดเวลาในการวิเคราะห์คำถาม",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "วิธีการของคำขอ",
|
||||
"request-schema-field": "ฟิลด์สคีมาของคำขอ",
|
||||
"request-tag-plural": "แท็กคำขอ",
|
||||
"required": "Required",
|
||||
"requirement-plural": "ข้อกำหนด",
|
||||
"reset": "รีเซ็ต",
|
||||
"reset-default-layout": "รีเซ็ตเลย์เอาต์เริ่มต้น",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Rules Evaluated",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "รัน",
|
||||
"run-agent-plural": "รันเอเจนต์",
|
||||
"run-at": "รันที่",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "สินทรัพย์ข้อมูลเฉพาะ",
|
||||
"spreadsheet": "สเปรดชีต",
|
||||
"spreadsheet-plural": "สเปรดชีต",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "ฟังก์ชัน SQL",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "คำสั่ง SQL",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "วันอาทิตย์",
|
||||
"support": "สนับสนุน",
|
||||
"support-url": "URL การสนับสนุน",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "ภาษาที่รองรับ",
|
||||
"switch-persona": "สลับเปอร์โซนา",
|
||||
"sync-alert-offset": "ซิงค์การแจ้งเตือน",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "กรณีทดสอบหลายรายการ",
|
||||
"test-case-resolution-status": "สถานะการแก้ไขกรณีทดสอบ",
|
||||
"test-case-result": "ผลกรณีทดสอบ",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "อีเมลทดสอบ",
|
||||
"test-email-connection": "ทดสอบการเชื่อมต่ออีเมล",
|
||||
"test-entity": "ทดสอบ {{entity}}",
|
||||
"test-level-lowercase": "ระดับการทดสอบ",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "การทดสอบหลายรายการ",
|
||||
"test-plural-type": "การทดสอบ {{type}}",
|
||||
"test-suite": "ชุดทดสอบ",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "นำเข้าข้อมูลเมตาจากบริการจัดเก็บที่ได้รับความนิยมมากที่สุด",
|
||||
"page-sub-header-for-table-profile": "ติดตามและเข้าใจโครงสร้างตารางของคุณด้วยโปรไฟล์เลอร์",
|
||||
"page-sub-header-for-teams": "แสดงโครงสร้างองค์กรของคุณทั้งหมดด้วยทีมที่มีลำดับชั้น",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "จัดการผู้ใช้ทั่วไปในองค์กรของคุณ สำหรับผู้ดูแลระบบ โปรดไปที่หน้าผู้ดูแลระบบ",
|
||||
"paid-addon-description": "<0>{{app}}</0> เป็นส่วนเสริมที่ต้องชำระเงินสำหรับลูกค้า Collate",
|
||||
"passed-x-checks": "Passed {{count}} checks",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "เพื่อเพิ่มคำพ้อง เพียงแค่พิมพ์และกด Enter",
|
||||
"system-alert-edit-message": "ไม่อนุญาตให้แก้ไขการแจ้งเตือนที่สร้างโดยระบบ",
|
||||
"system-tag-delete-disable-message": "ไม่อนุญาตให้ลบแท็กที่สร้างโดยระบบ คุณสามารถลองปิดใช้งานแทน",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "คุณต้องการดำเนินการอัปเดตแท็กหรือไม่?",
|
||||
"tailor-experience-for-persona": "ปรับแต่งประสบการณ์เฉพาะสำหรับบุคลิกภาพ {{persona}} ลองดูสิ!",
|
||||
"take-quick-product-tour": "เข้าร่วมทัวร์ผลิตภัณฑ์เพื่อเริ่มต้น!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "โปรดตรวจสอบว่าได้กำหนดค่าของ {{service_type}} ให้อนุญาตการเชื่อมต่อแล้ว",
|
||||
"withIp": " จาก {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "ทดสอบการเชื่อมต่อของคุณก่อนที่จะสร้างบริการ",
|
||||
"testing-your-connection-may-take-two-minutes": "การทดสอบการเชื่อมต่ออาจใช้เวลาถึง 2 นาที",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "การกระทำนี้ไม่อนุญาตสำหรับเอนทิตีที่ถูกลบ",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "ลบ {{entity}} {{count}} รายการสำเร็จ",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" มีอยู่แล้ว การทำซ้ำ {{entityPlural}} ไม่ได้รับอนุญาต",
|
||||
"entity-already-exist-message-without-name": "มี {{entity}} ที่มีรายละเอียดที่ระบุไว้แล้ว การทำซ้ำ {{entityPlural}} ไม่ได้รับอนุญาต",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "เกิดข้อผิดพลาดขณะสร้าง {{entity}}",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "\"{{entity}}\" ถูกลบสำเร็จ!",
|
||||
"entity-details-fetch-error": "เกิดข้อผิดพลาดขณะดึงรายละเอียดสำหรับ {{entityType}} {{entityName}}",
|
||||
"entity-feed-fetch-error": "เกิดข้อผิดพลาดขณะดึงจำนวนฟีดของเอนทิตี!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "ถึงขีดจำกัดของ {{entity}} แล้ว",
|
||||
"entity-removing-error": "เกิดข้อผิดพลาดขณะลบ {{entity}}",
|
||||
"entity-unfollow-error": "เกิดข้อผิดพลาดขณะเลิกติดตาม {{entity}}",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "เกิดข้อผิดพลาดขณะอัปเดต {{entity}}",
|
||||
"error-selected-node-name-details": "เกิดข้อผิดพลาดขณะดึงรายละเอียด {{selectedNodeName}}",
|
||||
"error-while-renewing-id-token-with-message": "เกิดข้อผิดพลาดขณะต่ออายุโทเค็นไอดีจาก Auth0 SSO: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "งานถูกแก้ไขสำเร็จแล้ว",
|
||||
"team-moved-error": "เกิดข้อผิดพลาดขณะย้ายทีม",
|
||||
"test-connection-error": "เกิดข้อผิดพลาดขณะทดสอบการเชื่อมต่อ!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "ผู้ใช้ที่ไม่ได้รับอนุญาต! โปรดตรวจสอบอีเมลหรือรหัสผ่าน",
|
||||
"unexpected-error": "เกิดข้อผิดพลาดที่ไม่คาดคิดขึ้น",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "Veri Profilleyici Metrikleri",
|
||||
"data-proportion-plural": "Veri Oranları",
|
||||
"data-quality": "Veri Kalitesi",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "Veri Kalitesi Testi",
|
||||
"data-quality-test-plural": "Veri Kalitesi Testleri",
|
||||
"data-quartile-plural": "Veri Dörttebirleri",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "Özel ölçü birimini girin ve Enter'a basın",
|
||||
"enter-each-value-and-press-enter": "Her değeri girin ve Enter tuşuna basın",
|
||||
"enter-entity": "{{entity}} Girin",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "{{entity}} adı girin",
|
||||
"enter-entity-value": "{{entity}} Değeri Girin",
|
||||
"enter-field-description": "{{field}} açıklaması girin",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "Sayfa Bulunamadı",
|
||||
"page-views-by-data-asset-plural": "Veri Varlıklarına Göre Sayfa Görüntülemeleri",
|
||||
"parameter": "Parametre",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "Parametreler",
|
||||
"parent": "Üst",
|
||||
"parsing-timeout-limit": "Sorgu Ayrıştırma Zaman Aşımı Limiti",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "İstek Metodu",
|
||||
"request-schema-field": "İstek Şema Alanı",
|
||||
"request-tag-plural": "Etiket İste",
|
||||
"required": "Required",
|
||||
"requirement-plural": "Gereksinimler",
|
||||
"reset": "Sıfırla",
|
||||
"reset-default-layout": "Varsayılan Düzeni Sıfırla",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "Rules Evaluated",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "Çalıştır",
|
||||
"run-agent-plural": "Agent'ları Çalıştır",
|
||||
"run-at": "Şu zamanda çalıştır",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "Belirli Veri Varlıkları",
|
||||
"spreadsheet": "Hesap tablosu",
|
||||
"spreadsheet-plural": "Hesap tabloları",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL Fonksiyonu",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL Sorgusu",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "Pazar",
|
||||
"support": "Destek",
|
||||
"support-url": "Destek URL'si",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "Desteklenen Diller",
|
||||
"switch-persona": "Persona Değiştir",
|
||||
"sync-alert-offset": "Senkronizasyon Uyarısı Ofseti",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "Test Senaryoları",
|
||||
"test-case-resolution-status": "Test Durumu Çözüm Durumu",
|
||||
"test-case-result": "Test Senaryosu Sonuçları",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "Test E-postası",
|
||||
"test-email-connection": "Test E-posta Bağlantısı",
|
||||
"test-entity": "Test {{entity}}",
|
||||
"test-level-lowercase": "test seviyesi",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "Testler",
|
||||
"test-plural-type": "{{type}} Testleri",
|
||||
"test-suite": "Test Paketi",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "En popüler depolama servislerinden metadata alın.",
|
||||
"page-sub-header-for-table-profile": "Profilleyici ile tablo yapınızı izleyin ve anlayın.",
|
||||
"page-sub-header-for-teams": "Hiyerarşik takımlarla tüm organizasyon yapınızı temsil edin.",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "Kuruluşunuzdaki normal kullanıcıları görüntüleyin ve yönetin. Yönetici kullanıcılar için lütfen Yönetici sayfasını ziyaret edin.",
|
||||
"paid-addon-description": "<0>{{app}}</0>, Collate müşterileri için ücretli bir eklentidir.",
|
||||
"passed-x-checks": "{{count}} kontrol geçildi",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "Bir eş anlamlı eklemek için yazın ve Enter tuşuna basın",
|
||||
"system-alert-edit-message": "Sistem tarafından oluşturulan bir uyarıyı düzenlemeye izin verilmez.",
|
||||
"system-tag-delete-disable-message": "Sistem tarafından oluşturulan etiketleri silmeye izin verilmez. Bunun yerine etiketi devre dışı bırakmayı deneyebilirsiniz.",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "Etiketleri güncellemekle devam etmek istiyor musunuz?",
|
||||
"tailor-experience-for-persona": "Deneyimi özellikle {{persona}} kişiliği için uyarlayın, deneyin!",
|
||||
"take-quick-product-tour": "Başlamak için hızlı bir ürün turuna katılın!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "Lütfen {{service_type}}'in bağlantılara izin verecek şekilde yapılandırıldığından emin olun",
|
||||
"withIp": " {{ip}} adresinden"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "Servisi oluşturmadan önce bağlantılarınızı test edin",
|
||||
"testing-your-connection-may-take-two-minutes": "Bağlantılarınızı test etmek 2 dakika kadar sürebilir",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "Bu eylem silinmiş varlıklar için izin verilmez.",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "{{count}} {{entity}} başarıyla silindi",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" zaten mevcut. Yinelenen {{entityPlural}} öğelerine izin verilmez.",
|
||||
"entity-already-exist-message-without-name": "Verilen ayrıntılara sahip bir {{entity}} zaten mevcut. Yinelenen {{entityPlural}} öğelerine izin verilmez.",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "{{entity}} oluşturulurken hata oluştu",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "\"{{entity}}\" başarıyla silindi!",
|
||||
"entity-details-fetch-error": "{{entityType}} {{entityName}} için ayrıntılar alınırken hata oluştu",
|
||||
"entity-feed-fetch-error": "Varlık akış sayısı alınırken hata oluştu!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} sınırına ulaşıldı",
|
||||
"entity-removing-error": "{{entity}} kaldırılırken hata oluştu",
|
||||
"entity-unfollow-error": "{{entity}} takibi bırakılırken hata oluştu",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "{{entity}} güncellenirken hata oluştu",
|
||||
"error-selected-node-name-details": "{{selectedNodeName}} ayrıntıları alınırken hata oluştu",
|
||||
"error-while-renewing-id-token-with-message": "Auth0 SSO'dan kimlik anahtarı yenilenirken hata oluştu: {{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "Görev başarıyla çözüldü",
|
||||
"team-moved-error": "Takım taşınırken hata oluştu",
|
||||
"test-connection-error": "Bağlantı test edilirken hata oluştu!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "Yetkisiz kullanıcı! lütfen e-postayı veya şifreyi kontrol edin",
|
||||
"unexpected-error": "Beklenmedik bir hata oluştu.",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "数据分析器指标",
|
||||
"data-proportion-plural": "数据比例",
|
||||
"data-quality": "数据质控",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "数据质控测试",
|
||||
"data-quality-test-plural": "总测试数",
|
||||
"data-quartile-plural": "数据四分位数",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "输入自定义计量单位并按Enter键",
|
||||
"enter-each-value-and-press-enter": "输入每个值并按Enter键",
|
||||
"enter-entity": "输入{{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "输入{{entity}}的名称",
|
||||
"enter-entity-value": "输入{{entity}}的值",
|
||||
"enter-field-description": "输入{{field}}的描述",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "没有找到页面",
|
||||
"page-views-by-data-asset-plural": "数据资产页面浏览量",
|
||||
"parameter": "参数",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "参数",
|
||||
"parent": "父级",
|
||||
"parsing-timeout-limit": "查询语句解析超时限制",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "Request Method",
|
||||
"request-schema-field": "Request Schema Field",
|
||||
"request-tag-plural": "请求补充标签",
|
||||
"required": "Required",
|
||||
"requirement-plural": "需求",
|
||||
"reset": "重置",
|
||||
"reset-default-layout": "重置默认布局",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- Rule: {{ruleName}}",
|
||||
"rules-count": "({{count}} rules)",
|
||||
"rules-evaluated": "已评估规则",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "运行",
|
||||
"run-agent-plural": "运行代理",
|
||||
"run-at": "运行于",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "特定数据资产",
|
||||
"spreadsheet": "电子表格",
|
||||
"spreadsheet-plural": "电子表格",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL函数",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL查询",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "星期天",
|
||||
"support": "支持",
|
||||
"support-url": "支持 URL",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "支持的语言",
|
||||
"switch-persona": "切换角色",
|
||||
"sync-alert-offset": "同步警报",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "测试用例",
|
||||
"test-case-resolution-status": "测试用例解决状态",
|
||||
"test-case-result": "测试用例结果",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "测试邮箱",
|
||||
"test-email-connection": "测试邮箱连接",
|
||||
"test-entity": "测试{{entity}}",
|
||||
"test-level-lowercase": "测试级别",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "测试",
|
||||
"test-plural-type": "{{type}}测试",
|
||||
"test-suite": "质控测试集",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "从最流行的存储类型服务中提取元数据",
|
||||
"page-sub-header-for-table-profile": "通过数据分析工具了解和跟踪您的数据表结构",
|
||||
"page-sub-header-for-teams": "将组织机构的架构通过团队进行分层分级",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "管理您组织中的普通用户。如需管理管理员,请访问管理员页面。",
|
||||
"paid-addon-description": "<0>{{app}}</0>是Collate客户的付费附加组件。",
|
||||
"passed-x-checks": "通过 {{count}} 项检查",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "输入并按回车键以新增一个同义词",
|
||||
"system-alert-edit-message": "不允许编辑系统生成的告警。",
|
||||
"system-tag-delete-disable-message": "无法删除系统默认的标签, 您可以尝试禁用标签",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "您要继续更新标签吗?",
|
||||
"tailor-experience-for-persona": "为{{persona}}角色量身定制体验,试试看!",
|
||||
"take-quick-product-tour": "快速查看产品导览",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "请确保 {{service_type}} 已配置为允许连接",
|
||||
"withIp": " 来自 {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "在创建服务之前测试您的连接",
|
||||
"testing-your-connection-may-take-two-minutes": "连接测试可能最多需要 2 分钟",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "已删除的实体不允许执行此操作",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "成功删除{{count}}个{{entity}}",
|
||||
"entity-already-exist": "与该名称\"{{name}}\"同名的{{entity}}已经存在, 不允许重名",
|
||||
"entity-already-exist-message-without-name": "已存在相同细节的{{entity}}, 不允许重复",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "创建{{entity}}时发生错误",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "{{entity}}删除成功!",
|
||||
"entity-details-fetch-error": "获取{{entityType}}{{entityName}}的详细信息时发生错误!",
|
||||
"entity-feed-fetch-error": "在获取信息流计数信息时发生错误!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} limit reached",
|
||||
"entity-removing-error": "删除{{entity}}时发生错误",
|
||||
"entity-unfollow-error": "取消关注{{entity}}时发生错误",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "更新{{entity}}时发生错误",
|
||||
"error-selected-node-name-details": "获取{{selectedNodeName}}详细信息时发生错误",
|
||||
"error-while-renewing-id-token-with-message": "从 Auth0 SSO 续订 ID 令牌时发生错误:{{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "任务已成功解决",
|
||||
"team-moved-error": "移动团队时发生错误",
|
||||
"test-connection-error": "测试连接时发生错误!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "未经授权的用户! 请检查电子邮箱或密码",
|
||||
"unexpected-error": "发生意外错误",
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
"data-profiler-metrics": "資料分析器指標",
|
||||
"data-proportion-plural": "資料比例",
|
||||
"data-quality": "資料品質",
|
||||
"data-quality-dimension": "Data Quality Dimension",
|
||||
"data-quality-test": "資料品質測試",
|
||||
"data-quality-test-plural": "資料品質測試",
|
||||
"data-quartile-plural": "資料四分位數",
|
||||
|
|
@ -613,6 +614,7 @@
|
|||
"enter-custom-unit-of-measurement": "輸入自訂計量單位並按Enter鍵",
|
||||
"enter-each-value-and-press-enter": "輸入每個值並按Enter鍵",
|
||||
"enter-entity": "輸入 {{entity}}",
|
||||
"enter-entity-description": "Enter {{entity}} description",
|
||||
"enter-entity-name": "輸入 {{entity}} 名稱",
|
||||
"enter-entity-value": "輸入 {{entity}} 值",
|
||||
"enter-field-description": "輸入 {{field}} 描述",
|
||||
|
|
@ -1253,6 +1255,9 @@
|
|||
"page-not-found": "找不到頁面",
|
||||
"page-views-by-data-asset-plural": "依資料資產的頁面瀏覽量",
|
||||
"parameter": "參數",
|
||||
"parameter-description": "Parameter Description",
|
||||
"parameter-display-name": "Parameter Display Name",
|
||||
"parameter-name": "Parameter Name",
|
||||
"parameter-plural": "參數",
|
||||
"parent": "父項",
|
||||
"parsing-timeout-limit": "查詢剖析逾時限制",
|
||||
|
|
@ -1436,6 +1441,7 @@
|
|||
"request-method": "請求方法",
|
||||
"request-schema-field": "請求結構欄位",
|
||||
"request-tag-plural": "請求標籤",
|
||||
"required": "Required",
|
||||
"requirement-plural": "需求",
|
||||
"reset": "重設",
|
||||
"reset-default-layout": "重設預設版面配置",
|
||||
|
|
@ -1495,6 +1501,7 @@
|
|||
"rule-with-name": "- 規則:{{ruleName}}",
|
||||
"rules-count": "({{count}} 個規則)",
|
||||
"rules-evaluated": "已評估的規則",
|
||||
"rules-library": "Rules Library",
|
||||
"run": "執行",
|
||||
"run-agent-plural": "執行代理程式",
|
||||
"run-at": "執行於",
|
||||
|
|
@ -1645,7 +1652,9 @@
|
|||
"specific-data-asset-plural": "特定資料資產",
|
||||
"spreadsheet": "試算表",
|
||||
"spreadsheet-plural": "試算表",
|
||||
"sql-expression": "SQL Expression",
|
||||
"sql-function": "SQL 函數",
|
||||
"sql-query": "SQL Query",
|
||||
"sql-uppercase": "SQL",
|
||||
"sql-uppercase-query": "SQL 查詢",
|
||||
"sso": "sso",
|
||||
|
|
@ -1705,6 +1714,7 @@
|
|||
"sunday": "星期日",
|
||||
"support": "支援",
|
||||
"support-url": "支援 URL",
|
||||
"supported-data-type-plural": "Supported Data Types",
|
||||
"supported-language-plural": "支援的語言",
|
||||
"switch-persona": "切換角色",
|
||||
"sync-alert-offset": "同步警示",
|
||||
|
|
@ -1770,10 +1780,13 @@
|
|||
"test-case-plural": "測試案例",
|
||||
"test-case-resolution-status": "測試案例解決狀態",
|
||||
"test-case-result": "測試案例結果",
|
||||
"test-definition": "Test Definition",
|
||||
"test-definition-plural": "Test Definitions",
|
||||
"test-email": "測試電子郵件",
|
||||
"test-email-connection": "測試電子郵件連線",
|
||||
"test-entity": "測試 {{entity}}",
|
||||
"test-level-lowercase": "測試層級",
|
||||
"test-platform-plural": "Test Platforms",
|
||||
"test-plural": "測試",
|
||||
"test-plural-type": "{{type}}測試",
|
||||
"test-suite": "測試套件",
|
||||
|
|
@ -2534,6 +2547,7 @@
|
|||
"page-sub-header-for-storages": "從最受歡迎的儲存服務擷取元資料。",
|
||||
"page-sub-header-for-table-profile": "使用分析器監控和了解您的資料表結構。",
|
||||
"page-sub-header-for-teams": "用階層式團隊代表您的整個組織結構。",
|
||||
"page-sub-header-for-test-definitions": "Manage and configure test definitions for data quality rules.",
|
||||
"page-sub-header-for-users": "檢視和管理您組織中的一般使用者。對於管理員使用者,請造訪管理員頁面。",
|
||||
"paid-addon-description": "<0>{{app}}</0> 是 Collate 客戶的付費附加元件。",
|
||||
"passed-x-checks": "通過 {{count}} 個檢查",
|
||||
|
|
@ -2660,6 +2674,8 @@
|
|||
"synonym-placeholder": "若要新增同義詞,只需輸入並按 Enter",
|
||||
"system-alert-edit-message": "不允許編輯系統產生的警示。",
|
||||
"system-tag-delete-disable-message": "不允許刪除系統產生的標籤。您可以嘗試停用該標籤。",
|
||||
"system-test-definition-delete-warning": "Deleting a system generated test definition is not allowed.",
|
||||
"system-test-definition-edit-warning": "Editing a system generated test definition is not allowed.",
|
||||
"tag-update-confirmation": "您想繼續更新標籤嗎?",
|
||||
"tailor-experience-for-persona": "專為 {{persona}} 角色量身打造體驗,試試看吧!",
|
||||
"take-quick-product-tour": "進行產品導覽以開始!",
|
||||
|
|
@ -2675,6 +2691,8 @@
|
|||
"default": "請確保 {{service_type}} 已設定為允許連線",
|
||||
"withIp": "從 {{ip}}"
|
||||
},
|
||||
"test-definition-parameters-description": "Defines configurable input parameters for test cases. Each parameter includes a name, data type (string, int, date, etc.), display name, and optional validation rules. Parameters can be referenced in SQL expressions using {{paramName}} syntax and allow users to customize test behavior when creating test cases.",
|
||||
"test-definition-sql-query-help": "SQL expression template for custom SQL-based test definitions. Supports substitution variables: {table} and {column} for runtime entity references, and {{paramName}} for user-defined parameters. This field is only applicable for test definitions with testPlatforms set to 'OpenMetadata' and is used to execute custom SQL queries for data quality validation.",
|
||||
"test-your-connection-before-creating-service": "在建立服務之前測試您的連線",
|
||||
"testing-your-connection-may-take-two-minutes": "測試您的連線最多可能需要 2 分鐘",
|
||||
"this-action-is-not-allowed-for-deleted-entities": "此操作不允許用於已刪除的實體。",
|
||||
|
|
@ -2774,7 +2792,9 @@
|
|||
"entities-deleted-successfully": "成功刪除{{count}}個{{entity}}",
|
||||
"entity-already-exist": "{{entity}} \"{{name}}\" 已存在。不允許重複的 {{entityPlural}}。",
|
||||
"entity-already-exist-message-without-name": "具有相同詳細資料的 {{entity}} 已存在。不允許重複的 {{entityPlural}}。",
|
||||
"entity-created-success": "{{entity}} created successfully!",
|
||||
"entity-creation-error": "建立 {{entity}} 時發生錯誤",
|
||||
"entity-deleted-success": "{{entity}} deleted successfully!",
|
||||
"entity-deleted-successfully": "\"{{entity}}\" 刪除成功!",
|
||||
"entity-details-fetch-error": "擷取 {{entityType}} {{entityName}} 詳細資料時發生錯誤",
|
||||
"entity-feed-fetch-error": "擷取實體摘要計數時發生錯誤!",
|
||||
|
|
@ -2784,6 +2804,7 @@
|
|||
"entity-limit-reached": "{{entity}} 已達上限",
|
||||
"entity-removing-error": "移除 {{entity}} 時發生錯誤",
|
||||
"entity-unfollow-error": "取消追蹤 {{entity}} 時發生錯誤",
|
||||
"entity-updated-success": "{{entity}} updated successfully!",
|
||||
"entity-updating-error": "更新 {{entity}} 時發生錯誤",
|
||||
"error-selected-node-name-details": "取得 {{selectedNodeName}} 詳細資料時發生錯誤",
|
||||
"error-while-renewing-id-token-with-message": "從 Auth0 SSO 更新 ID 權杖時發生錯誤:{{message}}",
|
||||
|
|
@ -2824,6 +2845,10 @@
|
|||
"task-resolved-successfully": "任務解決成功",
|
||||
"team-moved-error": "移動團隊時發生錯誤",
|
||||
"test-connection-error": "測試連線時發生錯誤!",
|
||||
"test-definition-parameters-description": "Define parameters that users can configure when creating test cases from this definition. Parameters allow for flexible and reusable test definitions.",
|
||||
"test-definition-sql-expression-placeholder": "SELECT * FROM {table} WHERE {column} < {{minValue}} OR {column} > {{maxValue}}",
|
||||
"test-definition-sql-expression-tooltip": "SQL query template using parameter placeholders in double curly braces (e.g., {{paramName}}). Use {table} and {column} for runtime entity references.",
|
||||
"test-definition-sql-query-help": "Write SQL query template with substitution variables. Use {table} for table name, {column} for column name (resolved at runtime). Use {{paramName}} for user parameters defined below (e.g., {{minValue}}, {{maxValue}}).",
|
||||
"this-action-cannot-be-undone": "This action cannot be undone.",
|
||||
"unauthorized-user": "未經授權的使用者!請檢查電子郵件或密碼",
|
||||
"unexpected-error": "發生未預期的錯誤。",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2024 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 { render, screen } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import RulesLibraryPage from './RulesLibraryPage';
|
||||
|
||||
jest.mock(
|
||||
'../../components/RulesLibrary/TestDefinitionList/TestDefinitionList.component',
|
||||
() => ({
|
||||
__esModule: true,
|
||||
default: jest
|
||||
.fn()
|
||||
.mockImplementation(() => (
|
||||
<div data-testid="test-definition-list">TestDefinitionList</div>
|
||||
)),
|
||||
})
|
||||
);
|
||||
|
||||
jest.mock('../../components/PageLayoutV1/PageLayoutV1', () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn().mockImplementation(({ children, pageTitle }) => (
|
||||
<div data-testid="page-layout">
|
||||
<h1>{pageTitle}</h1>
|
||||
{children}
|
||||
</div>
|
||||
)),
|
||||
}));
|
||||
|
||||
describe('RulesLibraryPage Component', () => {
|
||||
it('should render page layout with correct title', () => {
|
||||
render(<RulesLibraryPage />, { wrapper: MemoryRouter });
|
||||
|
||||
expect(screen.getByTestId('page-layout')).toBeInTheDocument();
|
||||
expect(screen.getByText('label.rules-library')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render TestDefinitionList component', () => {
|
||||
render(<RulesLibraryPage />, { wrapper: MemoryRouter });
|
||||
|
||||
expect(screen.getByTestId('test-definition-list')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render with correct layout structure', () => {
|
||||
const { container } = render(<RulesLibraryPage />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const row = container.querySelector('.ant-row');
|
||||
|
||||
expect(row).toBeInTheDocument();
|
||||
|
||||
const col = container.querySelector('.ant-col-24');
|
||||
|
||||
expect(col).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2024 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 { Col, Row } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PageLayoutV1 from '../../components/PageLayoutV1/PageLayoutV1';
|
||||
import TestDefinitionList from '../../components/RulesLibrary/TestDefinitionList/TestDefinitionList.component';
|
||||
|
||||
const RulesLibraryPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<PageLayoutV1 pageTitle={t('label.rules-library')}>
|
||||
<Row className="p-t-md" gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<TestDefinitionList />
|
||||
</Col>
|
||||
</Row>
|
||||
</PageLayoutV1>
|
||||
);
|
||||
};
|
||||
|
||||
export default RulesLibraryPage;
|
||||
|
|
@ -17,6 +17,7 @@ import { PagingResponse } from 'Models';
|
|||
import { SORT_ORDER } from '../enums/common.enum';
|
||||
import { TestCaseType, TestSuiteType } from '../enums/TestSuite.enum';
|
||||
import { CreateTestCase } from '../generated/api/tests/createTestCase';
|
||||
import { CreateTestDefinition } from '../generated/api/tests/createTestDefinition';
|
||||
import { CreateTestSuite } from '../generated/api/tests/createTestSuite';
|
||||
import { DataQualityReport } from '../generated/tests/dataQualityReport';
|
||||
import {
|
||||
|
|
@ -78,8 +79,9 @@ export type ListTestCaseParamsBySearch = ListTestCaseParams & {
|
|||
|
||||
export type ListTestDefinitionsParams = ListParams & {
|
||||
entityType?: EntityType;
|
||||
testPlatform: TestPlatform;
|
||||
testPlatform?: TestPlatform;
|
||||
supportedDataType?: string;
|
||||
enabled?: boolean;
|
||||
};
|
||||
|
||||
export type ListTestCaseResultsParams = Omit<
|
||||
|
|
@ -279,6 +281,49 @@ export const getTestDefinitionById = async (
|
|||
return response.data;
|
||||
};
|
||||
|
||||
export const createTestDefinition = async (data: CreateTestDefinition) => {
|
||||
const response = await APIClient.post<TestDefinition>(
|
||||
testDefinitionUrl,
|
||||
data
|
||||
);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateTestDefinition = async (data: TestDefinition) => {
|
||||
const response = await APIClient.put<TestDefinition>(testDefinitionUrl, data);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const patchTestDefinition = async (id: string, patch: Operation[]) => {
|
||||
const response = await APIClient.patch<TestDefinition>(
|
||||
`${testDefinitionUrl}/${id}`,
|
||||
patch
|
||||
);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const deleteTestDefinitionByFqn = async (
|
||||
fqn: string,
|
||||
paramsValue?: { hardDelete?: boolean; recursive?: boolean }
|
||||
) => {
|
||||
const params = {
|
||||
hardDelete: true,
|
||||
recursive: true,
|
||||
...paramsValue,
|
||||
};
|
||||
const response = await APIClient.delete<TestDefinition>(
|
||||
`${testDefinitionUrl}/name/${fqn}`,
|
||||
{
|
||||
params,
|
||||
}
|
||||
);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// testSuite Section
|
||||
export const getListTestSuites = async (params?: ListTestSuitePrams) => {
|
||||
const response = await APIClient.get<{
|
||||
|
|
|
|||
Loading…
Reference in a new issue