Fix #18834: Introduce new setting OpenMetadataBaseUrlConfiguration to set the server endpoint (#19366)

* Refactor: Introduce openMetadataBaseUrlConfiguration to set up the server endpoint and remove OpenMetadataUrl from smtpSettings.json

* migrations.

* refactor(cli): add setOpenMetadataUrl command to store OpenMetadata URL

* refactor(cli): add configureEmailSettings command to manage SMTP/Email configuration

* load initialData when config is not present in the db

* add om url settings page

* update locales

* add e2e

* load omBaseUrl with default host and port: localhost:8585 when not present

---------

Co-authored-by: Karan Hotchandani <33024356+karanh37@users.noreply.github.com>
Co-authored-by: karanh37 <karanh37@gmail.com>
This commit is contained in:
Siddhant 2025-01-27 10:20:04 +05:30 committed by GitHub
parent e59ddecf28
commit 473688648b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
56 changed files with 1751 additions and 1087 deletions

View File

@ -0,0 +1,4 @@
-- remove openMetadataUrl from smtpSettings
UPDATE openmetadata_settings
SET json = JSON_REMOVE(json, '$.openMetadataUrl')
WHERE configType = 'emailConfiguration';

View File

@ -0,0 +1,4 @@
-- remove openMetadataUrl from smtpSettings
UPDATE openmetadata_settings
SET json = json - 'openMetadataUrl'
WHERE configType = 'emailConfiguration';

View File

@ -370,19 +370,6 @@ health:
failureAttempts: 2
successAttempts: 1
email:
emailingEntity: ${OM_EMAIL_ENTITY:-"OpenMetadata"}
supportUrl: ${OM_SUPPORT_URL:-"https://slack.open-metadata.org"}
enableSmtpServer : ${AUTHORIZER_ENABLE_SMTP:-false}
openMetadataUrl: ${OPENMETADATA_SERVER_URL:-"http://localhost:8585"}
senderMail: ${OPENMETADATA_SMTP_SENDER_MAIL:-""}
serverEndpoint: ${SMTP_SERVER_ENDPOINT:-""}
serverPort: ${SMTP_SERVER_PORT:-""}
username: ${SMTP_SERVER_USERNAME:-""}
password: ${SMTP_SERVER_PWD:-""}
transportationStrategy: ${SMTP_SERVER_STRATEGY:-"SMTP_TLS"}
templates: ${TEMPLATES:-"openmetadata"}
limits:
enable: ${LIMITS_ENABLED:-false}
className: ${LIMITS_CLASS_NAME:-"org.openmetadata.service.limits.DefaultLimits"}

View File

@ -31,7 +31,6 @@ import org.openmetadata.schema.api.security.AuthenticationConfiguration;
import org.openmetadata.schema.api.security.AuthorizerConfiguration;
import org.openmetadata.schema.api.security.jwt.JWTTokenConfiguration;
import org.openmetadata.schema.configuration.LimitsConfiguration;
import org.openmetadata.schema.email.SmtpSettings;
import org.openmetadata.schema.security.secrets.SecretsManagerConfiguration;
import org.openmetadata.schema.service.configuration.elasticsearch.ElasticSearchConfiguration;
import org.openmetadata.service.config.OMWebConfiguration;
@ -102,9 +101,6 @@ public class OpenMetadataApplicationConfig extends Configuration {
@JsonProperty("clusterName")
private String clusterName;
@JsonProperty("email")
private SmtpSettings smtpSettings;
@Valid
@NotNull
@JsonProperty("web")

View File

@ -14,7 +14,6 @@
package org.openmetadata.service.formatter.decorators;
import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty;
import static org.openmetadata.service.util.email.EmailUtil.getSmtpSettings;
import java.util.ArrayList;
import java.util.Collections;
@ -22,6 +21,7 @@ import org.apache.commons.lang3.StringUtils;
import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.service.apps.bundles.changeEvent.email.EmailMessage;
import org.openmetadata.service.exception.UnhandledServerException;
import org.openmetadata.service.util.email.EmailUtil;
public class EmailMessageDecorator implements MessageDecorator<EmailMessage> {
@Override
@ -63,7 +63,7 @@ public class EmailMessageDecorator implements MessageDecorator<EmailMessage> {
public String getEntityUrl(String prefix, String fqn, String additionalParams) {
return String.format(
"<a href = '%s/%s/%s%s'>%s</a>",
getSmtpSettings().getOpenMetadataUrl(),
EmailUtil.getOMBaseURL(),
prefix,
fqn.trim(),
nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams),

View File

@ -14,7 +14,6 @@
package org.openmetadata.service.formatter.decorators;
import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty;
import static org.openmetadata.service.util.email.EmailUtil.getSmtpSettings;
import java.util.ArrayList;
import java.util.Arrays;
@ -36,6 +35,7 @@ import org.openmetadata.service.Entity;
import org.openmetadata.service.apps.bundles.changeEvent.gchat.GChatMessage;
import org.openmetadata.service.apps.bundles.changeEvent.gchat.GChatMessage.*;
import org.openmetadata.service.exception.UnhandledServerException;
import org.openmetadata.service.util.email.EmailUtil;
public class GChatMessageDecorator implements MessageDecorator<GChatMessage> {
@ -78,7 +78,7 @@ public class GChatMessageDecorator implements MessageDecorator<GChatMessage> {
public String getEntityUrl(String prefix, String fqn, String additionalParams) {
return String.format(
"<%s/%s/%s%s|%s>",
getSmtpSettings().getOpenMetadataUrl(),
EmailUtil.getOMBaseURL(),
prefix,
fqn.trim().replace(" ", "%20"),
nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams),

View File

@ -14,7 +14,6 @@
package org.openmetadata.service.formatter.decorators;
import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty;
import static org.openmetadata.service.util.email.EmailUtil.getSmtpSettings;
import java.util.ArrayList;
import java.util.Arrays;
@ -40,6 +39,7 @@ import org.openmetadata.service.apps.bundles.changeEvent.msteams.TeamsMessage.Co
import org.openmetadata.service.apps.bundles.changeEvent.msteams.TeamsMessage.Image;
import org.openmetadata.service.apps.bundles.changeEvent.msteams.TeamsMessage.TextBlock;
import org.openmetadata.service.exception.UnhandledServerException;
import org.openmetadata.service.util.email.EmailUtil;
public class MSTeamsMessageDecorator implements MessageDecorator<TeamsMessage> {
private static final String TEST_CASE_RESULT = "testCaseResult";
@ -84,7 +84,7 @@ public class MSTeamsMessageDecorator implements MessageDecorator<TeamsMessage> {
return String.format(
"[%s](/%s/%s%s)",
fqn.trim(),
getSmtpSettings().getOpenMetadataUrl(),
EmailUtil.getOMBaseURL(),
prefix,
nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams));
}

View File

@ -14,7 +14,6 @@
package org.openmetadata.service.formatter.decorators;
import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty;
import static org.openmetadata.service.util.email.EmailUtil.getSmtpSettings;
import com.slack.api.model.block.Blocks;
import com.slack.api.model.block.LayoutBlock;
@ -39,6 +38,7 @@ import org.openmetadata.schema.type.TagLabel;
import org.openmetadata.service.Entity;
import org.openmetadata.service.apps.bundles.changeEvent.slack.SlackMessage;
import org.openmetadata.service.exception.UnhandledServerException;
import org.openmetadata.service.util.email.EmailUtil;
public class SlackMessageDecorator implements MessageDecorator<SlackMessage> {
@ -80,7 +80,7 @@ public class SlackMessageDecorator implements MessageDecorator<SlackMessage> {
public String getEntityUrl(String prefix, String fqn, String additionalParams) {
return String.format(
"<%s/%s/%s%s|%s>",
getSmtpSettings().getOpenMetadataUrl(),
EmailUtil.getOMBaseURL(),
prefix,
fqn.trim().replaceAll(" ", "%20"),
nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams),

View File

@ -60,6 +60,7 @@ import org.openmetadata.schema.TokenInterface;
import org.openmetadata.schema.analytics.ReportData;
import org.openmetadata.schema.analytics.WebAnalyticEvent;
import org.openmetadata.schema.api.configuration.LoginConfiguration;
import org.openmetadata.schema.api.configuration.OpenMetadataBaseUrlConfiguration;
import org.openmetadata.schema.api.configuration.profiler.ProfilerConfiguration;
import org.openmetadata.schema.api.lineage.LineageSettings;
import org.openmetadata.schema.api.search.SearchSettings;
@ -5308,6 +5309,8 @@ public interface CollectionDAO {
Object value =
switch (configType) {
case EMAIL_CONFIGURATION -> JsonUtils.readValue(json, SmtpSettings.class);
case OPEN_METADATA_BASE_URL_CONFIGURATION -> JsonUtils.readValue(
json, OpenMetadataBaseUrlConfiguration.class);
case CUSTOM_UI_THEME_PREFERENCE -> JsonUtils.readValue(json, UiThemePreference.class);
case LOGIN_CONFIGURATION -> JsonUtils.readValue(json, LoginConfiguration.class);
case SLACK_APP_CONFIGURATION, SLACK_INSTALLER, SLACK_BOT, SLACK_STATE -> JsonUtils

View File

@ -15,6 +15,7 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jdbi.v3.sqlobject.transaction.Transaction;
import org.openmetadata.api.configuration.UiThemePreference;
import org.openmetadata.schema.api.configuration.OpenMetadataBaseUrlConfiguration;
import org.openmetadata.schema.configuration.AssetCertificationSettings;
import org.openmetadata.schema.configuration.ExecutorConfiguration;
import org.openmetadata.schema.configuration.HistoryCleanUpConfiguration;
@ -175,6 +176,22 @@ public class SystemRepository {
return null;
}
public Settings getOMBaseUrlConfigInternal() {
try {
Settings setting =
dao.getConfigWithKey(SettingsType.OPEN_METADATA_BASE_URL_CONFIGURATION.value());
OpenMetadataBaseUrlConfiguration urlConfiguration =
(OpenMetadataBaseUrlConfiguration) setting.getConfigValue();
setting.setConfigValue(urlConfiguration);
return setting;
} catch (Exception ex) {
LOG.error(
"Error while trying to fetch OpenMetadataBaseUrlConfiguration Settings {}",
ex.getMessage());
}
return null;
}
public Settings getSlackApplicationConfigInternal() {
try {
Settings setting = dao.getConfigWithKey(SettingsType.SLACK_APP_CONFIGURATION.value());
@ -269,6 +286,11 @@ public class SystemRepository {
SmtpSettings emailConfig =
JsonUtils.convertValue(setting.getConfigValue(), SmtpSettings.class);
setting.setConfigValue(encryptEmailSetting(emailConfig));
} else if (setting.getConfigType() == SettingsType.OPEN_METADATA_BASE_URL_CONFIGURATION) {
OpenMetadataBaseUrlConfiguration omBaseUrl =
JsonUtils.convertValue(
setting.getConfigValue(), OpenMetadataBaseUrlConfiguration.class);
setting.setConfigValue(omBaseUrl);
} else if (setting.getConfigType() == SettingsType.SLACK_APP_CONFIGURATION) {
SlackAppConfiguration appConfiguration =
JsonUtils.convertValue(setting.getConfigValue(), SlackAppConfiguration.class);

View File

@ -18,9 +18,11 @@ import static org.openmetadata.schema.settings.SettingsType.CUSTOM_UI_THEME_PREF
import static org.openmetadata.schema.settings.SettingsType.EMAIL_CONFIGURATION;
import static org.openmetadata.schema.settings.SettingsType.LINEAGE_SETTINGS;
import static org.openmetadata.schema.settings.SettingsType.LOGIN_CONFIGURATION;
import static org.openmetadata.schema.settings.SettingsType.OPEN_METADATA_BASE_URL_CONFIGURATION;
import static org.openmetadata.schema.settings.SettingsType.SEARCH_SETTINGS;
import static org.openmetadata.schema.settings.SettingsType.WORKFLOW_SETTINGS;
import com.cronutils.utils.StringUtils;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
@ -28,10 +30,12 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.CheckForNull;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
import org.openmetadata.api.configuration.LogoConfiguration;
import org.openmetadata.api.configuration.ThemeConfiguration;
import org.openmetadata.api.configuration.UiThemePreference;
import org.openmetadata.schema.api.configuration.LoginConfiguration;
import org.openmetadata.schema.api.configuration.OpenMetadataBaseUrlConfiguration;
import org.openmetadata.schema.api.lineage.LineageLayer;
import org.openmetadata.schema.api.lineage.LineageSettings;
import org.openmetadata.schema.api.search.SearchSettings;
@ -76,12 +80,35 @@ public class SettingsCache {
Settings storedSettings = systemRepository.getConfigWithKey(EMAIL_CONFIGURATION.toString());
if (storedSettings == null) {
// Only in case a config doesn't exist in DB we insert it
SmtpSettings emailConfig = applicationConfig.getSmtpSettings();
SmtpSettings emailConfig =
new SmtpSettings()
.withPassword(StringUtils.EMPTY)
.withEmailingEntity("OpenMetadata")
.withSupportUrl("https://slack.open-metadata.org")
.withEnableSmtpServer(Boolean.FALSE)
.withTransportationStrategy(SmtpSettings.TransportationStrategy.SMTP_TLS)
.withTemplates(SmtpSettings.Templates.OPENMETADATA);
Settings setting =
new Settings().withConfigType(EMAIL_CONFIGURATION).withConfigValue(emailConfig);
systemRepository.createNewSetting(setting);
}
// Initialise OM base url setting
Settings storedOpenMetadataBaseUrlConfiguration =
systemRepository.getConfigWithKey(OPEN_METADATA_BASE_URL_CONFIGURATION.toString());
if (storedOpenMetadataBaseUrlConfiguration == null) {
String url =
new HttpUrl.Builder().scheme("http").host("localhost").port(8585).build().toString();
String baseUrl = url.substring(0, url.length() - 1);
Settings setting =
new Settings()
.withConfigType(OPEN_METADATA_BASE_URL_CONFIGURATION)
.withConfigValue(new OpenMetadataBaseUrlConfiguration().withOpenMetadataUrl(baseUrl));
systemRepository.createNewSetting(setting);
}
// Initialise Theme Setting
Settings storedCustomUiThemeConf =
systemRepository.getConfigWithKey(CUSTOM_UI_THEME_PREFERENCE.toString());
@ -208,6 +235,9 @@ public class SettingsCache {
fetchedSettings = systemRepository.getEmailConfigInternal();
LOG.info("Loaded Email Setting");
}
case OPEN_METADATA_BASE_URL_CONFIGURATION -> {
fetchedSettings = systemRepository.getOMBaseUrlConfigInternal();
}
case SLACK_APP_CONFIGURATION -> {
// Only if available
fetchedSettings = systemRepository.getSlackApplicationConfigInternal();

View File

@ -255,30 +255,6 @@ public class SystemResource {
return systemRepository.patchSetting(settingName, patch);
}
@PUT
@Path("/restore/default/email")
@Operation(
operationId = "restoreEmailSettingToDefault",
summary = "Restore Email to Default setting",
description = "Restore Email to Default settings",
responses = {
@ApiResponse(
responseCode = "200",
description = "Settings",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Settings.class)))
})
public Response restoreDefaultEmailSetting(
@Context UriInfo uriInfo, @Context SecurityContext securityContext) {
authorizer.authorizeAdmin(securityContext);
return systemRepository.createOrUpdate(
new Settings()
.withConfigType(SettingsType.EMAIL_CONFIGURATION)
.withConfigValue(applicationConfig.getSmtpSettings()));
}
@GET
@Path("/entities/count")
@Operation(

View File

@ -183,7 +183,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
String emailVerificationLink =
String.format(
"%s/users/registrationConfirmation?user=%s&token=%s",
getSmtpSettings().getOpenMetadataUrl(),
EmailUtil.getOMBaseURL(),
URLEncoder.encode(user.getFullyQualifiedName(), StandardCharsets.UTF_8),
mailVerificationToken);
try {
@ -207,7 +207,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
String passwordResetLink =
String.format(
"%s/users/password/reset?user=%s&token=%s",
getSmtpSettings().getOpenMetadataUrl(),
EmailUtil.getOMBaseURL(),
URLEncoder.encode(user.getName(), StandardCharsets.UTF_8),
mailVerificationToken);
try {
@ -339,7 +339,7 @@ public class BasicAuthenticator implements AuthenticatorHandler {
templatePopulator.put(SUPPORT_URL, getSmtpSettings().getSupportUrl());
templatePopulator.put(USERNAME, user.getName());
templatePopulator.put(PASSWORD, pwd);
templatePopulator.put(APPLICATION_LOGIN_LINK, getSmtpSettings().getOpenMetadataUrl());
templatePopulator.put(APPLICATION_LOGIN_LINK, EmailUtil.getOMBaseURL());
try {
EmailUtil.sendMail(
subject, templatePopulator, user.getEmail(), INVITE_RANDOM_PASSWORD_TEMPLATE, true);

View File

@ -44,6 +44,8 @@ import org.flywaydb.core.api.MigrationVersion;
import org.jdbi.v3.core.Jdbi;
import org.openmetadata.schema.EntityInterface;
import org.openmetadata.schema.ServiceEntityInterface;
import org.openmetadata.schema.api.configuration.OpenMetadataBaseUrlConfiguration;
import org.openmetadata.schema.email.SmtpSettings;
import org.openmetadata.schema.entity.app.App;
import org.openmetadata.schema.entity.app.AppConfiguration;
import org.openmetadata.schema.entity.app.AppMarketPlaceDefinition;
@ -180,20 +182,144 @@ public class OpenMetadataOperations implements Callable<Integer> {
}
@Command(
name = "syncEmailFromEnv",
description = "Sync the email configuration from environment variables")
public Integer syncEmailFromEnv() {
name = "setOpenMetadataUrl",
description = "Set or update the OpenMetadata URL in the system repository")
public Integer setOpenMetadataUrl(
@Option(
names = {"-u", "--url"},
description = "OpenMetadata URL to store in the system repository",
required = true)
String openMetadataUrl) {
try {
parseConfig();
Settings updatedSettings =
new Settings()
.withConfigType(SettingsType.EMAIL_CONFIGURATION)
.withConfigValue(config.getSmtpSettings());
.withConfigType(SettingsType.OPEN_METADATA_BASE_URL_CONFIGURATION)
.withConfigValue(
new OpenMetadataBaseUrlConfiguration().withOpenMetadataUrl(openMetadataUrl));
Entity.getSystemRepository().createOrUpdate(updatedSettings);
LOG.info("Synced Email Configuration from Environment.");
LOG.info("Updated OpenMetadata URL to: {}", openMetadataUrl);
return 0;
} catch (Exception e) {
LOG.error("Email Sync failed due to ", e);
LOG.error("Failed to set OpenMetadata URL due to: ", e);
return 1;
}
}
@Command(
name = "configureEmailSettings",
description =
"Set or update the SMTP/Email configuration in the OpenMetadata system repository")
public Integer configureEmailSettings(
@Option(
names = {"--emailingEntity"},
description = "Identifier or entity name used for sending emails (e.g. OpenMetadata)",
required = true)
String emailingEntity,
@Option(
names = {"--supportUrl"},
description =
"Support URL for help or documentation (e.g. https://slack.open-metadata.org)",
required = true)
String supportUrl,
@Option(
names = {"--enableSmtpServer"},
description = "Flag indicating whether SMTP server is enabled (true/false)",
required = true,
arity = "1")
boolean enableSmtpServer,
@Option(
names = {"--senderMail"},
description = "Sender email address used for outgoing messages",
required = true)
String senderMail,
@Option(
names = {"--serverEndpoint"},
description = "SMTP server endpoint (host)",
required = true)
String serverEndpoint,
@Option(
names = {"--serverPort"},
description = "SMTP server port",
required = true)
String serverPort,
@Option(
names = {"--username"},
description = "SMTP server username",
required = true)
String username,
@Option(
names = {"--password"},
description = "SMTP server password (may be masked)",
interactive = true,
arity = "0..1",
required = true)
char[] password,
@Option(
names = {"--transportationStrategy"},
description = "SMTP connection strategy (one of: SMTP, SMTPS, SMTP_TLS)",
required = true)
String transportationStrategy,
@Option(
names = {"--templatePath"},
description = "Custom path to email templates (if needed)")
String templatePath,
@Option(
names = {"--templates"},
description = "Email templates (e.g. openmetadata, collate)",
required = true)
String templates) {
try {
parseConfig();
SmtpSettings smtpSettings = new SmtpSettings();
smtpSettings.setEmailingEntity(emailingEntity);
smtpSettings.setSupportUrl(supportUrl);
smtpSettings.setEnableSmtpServer(enableSmtpServer);
smtpSettings.setSenderMail(senderMail);
smtpSettings.setServerEndpoint(serverEndpoint);
smtpSettings.setServerPort(Integer.parseInt(serverPort));
smtpSettings.setUsername(username);
smtpSettings.setPassword(password != null ? new String(password) : "");
try {
smtpSettings.setTransportationStrategy(
SmtpSettings.TransportationStrategy.valueOf(transportationStrategy.toUpperCase()));
} catch (IllegalArgumentException e) {
LOG.warn(
"Invalid transportation strategy '{}'. Falling back to SMTP_TLS.",
transportationStrategy);
smtpSettings.setTransportationStrategy(SmtpSettings.TransportationStrategy.SMTP_TLS);
}
smtpSettings.setTemplatePath(templatePath);
try {
smtpSettings.setTemplates(SmtpSettings.Templates.valueOf(templates.toUpperCase()));
} catch (IllegalArgumentException e) {
LOG.warn("Invalid template value '{}'. Falling back to OPENMETADATA.", templates);
smtpSettings.setTemplates(SmtpSettings.Templates.OPENMETADATA);
}
Settings emailSettings =
new Settings()
.withConfigType(SettingsType.EMAIL_CONFIGURATION)
.withConfigValue(smtpSettings);
Entity.getSystemRepository().createOrUpdate(emailSettings);
LOG.info(
"Email settings updated. (Email Entity: {}, SMTP Enabled: {}, SMTP Host: {})",
emailingEntity,
enableSmtpServer,
serverEndpoint);
return 0;
} catch (Exception e) {
LOG.error("Failed to configure email settings due to: ", e);
return 1;
}
}

View File

@ -55,13 +55,16 @@ import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.openmetadata.common.utils.CommonUtil;
import org.openmetadata.schema.api.configuration.OpenMetadataBaseUrlConfiguration;
import org.openmetadata.schema.email.SmtpSettings;
import org.openmetadata.schema.entity.feed.Thread;
import org.openmetadata.schema.entity.teams.User;
import org.openmetadata.schema.settings.Settings;
import org.openmetadata.schema.settings.SettingsType;
import org.openmetadata.service.apps.bundles.changeEvent.email.EmailMessage;
import org.openmetadata.service.events.scheduled.template.DataInsightDescriptionAndOwnerTemplate;
import org.openmetadata.service.events.scheduled.template.DataInsightTotalAssetTemplate;
import org.openmetadata.service.jdbi3.SystemRepository;
import org.openmetadata.service.resources.settings.SettingsCache;
import org.simplejavamail.api.email.Email;
import org.simplejavamail.api.email.EmailPopulatingBuilder;
@ -277,7 +280,7 @@ public class EmailUtil {
.add(SUPPORT_URL, getSmtpSettings().getSupportUrl())
.add(USERNAME, user.getName())
.add(PASSWORD, password)
.add(APPLICATION_LOGIN_LINK, getSmtpSettings().getOpenMetadataUrl())
.add(APPLICATION_LOGIN_LINK, getOMBaseURL())
.build();
try {
@ -351,10 +354,7 @@ public class EmailUtil {
.add("descriptionObj", descriptionObj)
.add("ownershipObj", ownerShipObj)
.add("tierObj", tierObj)
.add(
"viewReportUrl",
String.format(
"%s/data-insights/data-assets", getSmtpSettings().getOpenMetadataUrl()))
.add("viewReportUrl", String.format("%s/data-insights/data-assets", getOMBaseURL()))
.build();
sendMailToMultiple(subject, templatePopulator, emails, templateFilePath);
@ -440,6 +440,15 @@ public class EmailUtil {
return email.matches("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$");
}
public static String getOMBaseURL() {
Settings setting =
new SystemRepository()
.getConfigWithKey(SettingsType.OPEN_METADATA_BASE_URL_CONFIGURATION.value());
OpenMetadataBaseUrlConfiguration urlConfiguration =
(OpenMetadataBaseUrlConfiguration) setting.getConfigValue();
return urlConfiguration.getOpenMetadataUrl();
}
static class TemplatePopulatorBuilder {
private final Map<String, Object> templatePopulator;

View File

@ -2,7 +2,6 @@ package org.openmetadata.service.resources.events;
import static org.junit.Assert.assertEquals;
import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty;
import static org.openmetadata.service.util.email.EmailUtil.getSmtpSettings;
import java.util.ArrayList;
import java.util.List;
@ -25,6 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import org.awaitility.Awaitility;
import org.openmetadata.common.utils.CommonUtil;
import org.openmetadata.service.util.RestUtil;
import org.openmetadata.service.util.email.EmailUtil;
@Slf4j
@Path("v1/test/slack")
@ -128,7 +128,7 @@ public class SlackCallbackResource {
public String getEntityUrl(String prefix, String fqn, String additionalParams) {
return String.format(
"<%s/%s/%s%s|%s>",
getSmtpSettings().getOpenMetadataUrl(),
EmailUtil.getOMBaseURL(),
prefix,
fqn.trim().replaceAll(" ", "%20"),
nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams),

View File

@ -1,7 +1,6 @@
package org.openmetadata.service.resources.system;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.openmetadata.service.util.TestUtils.ADMIN_AUTH_HEADERS;
import static org.openmetadata.service.util.TestUtils.TEST_AUTH_HEADERS;
@ -48,7 +47,6 @@ import org.openmetadata.schema.auth.JWTAuthMechanism;
import org.openmetadata.schema.auth.JWTTokenExpiry;
import org.openmetadata.schema.configuration.AssetCertificationSettings;
import org.openmetadata.schema.configuration.WorkflowSettings;
import org.openmetadata.schema.email.SmtpSettings;
import org.openmetadata.schema.entity.data.Table;
import org.openmetadata.schema.entity.teams.AuthenticationMechanism;
import org.openmetadata.schema.profiler.MetricType;
@ -58,10 +56,8 @@ import org.openmetadata.schema.system.ValidationResponse;
import org.openmetadata.schema.type.ColumnDataType;
import org.openmetadata.schema.util.EntitiesCount;
import org.openmetadata.schema.util.ServicesCount;
import org.openmetadata.service.Entity;
import org.openmetadata.service.OpenMetadataApplicationConfig;
import org.openmetadata.service.OpenMetadataApplicationTest;
import org.openmetadata.service.fernet.Fernet;
import org.openmetadata.service.resources.EntityResourceTest;
import org.openmetadata.service.resources.dashboards.DashboardResourceTest;
import org.openmetadata.service.resources.databases.TableResourceTest;
@ -81,7 +77,6 @@ import org.openmetadata.service.resources.storages.ContainerResourceTest;
import org.openmetadata.service.resources.teams.TeamResourceTest;
import org.openmetadata.service.resources.teams.UserResourceTest;
import org.openmetadata.service.resources.topics.TopicResourceTest;
import org.openmetadata.service.secrets.masker.PasswordEntityMasker;
import org.openmetadata.service.util.JsonUtils;
import org.openmetadata.service.util.TestUtils;
@ -188,14 +183,6 @@ public class SystemResourceTest extends OpenMetadataApplicationTest {
@Test
@Order(2)
void testSystemConfigs() throws HttpResponseException {
// Test Email Config
Settings emailSettings = getSystemConfig(SettingsType.EMAIL_CONFIGURATION);
SmtpSettings smtp = JsonUtils.convertValue(emailSettings.getConfigValue(), SmtpSettings.class);
// Password for Email is always sent in hidden
SmtpSettings expected = config.getSmtpSettings();
expected.setPassword(PasswordEntityMasker.PASSWORD_MASK);
assertEquals(expected, smtp);
// Test Custom Ui Theme Preference Config
Settings uiThemeConfigWrapped = getSystemConfig(SettingsType.CUSTOM_UI_THEME_PREFERENCE);
UiThemePreference uiThemePreference =
@ -211,40 +198,8 @@ public class SystemResourceTest extends OpenMetadataApplicationTest {
assertEquals("", uiThemePreference.getCustomLogoConfig().getCustomMonogramUrlPath());
}
@Test
@Order(1)
void testDefaultEmailSystemConfig() {
// Test Email Config
Settings stored =
Entity.getCollectionDAO()
.systemDAO()
.getConfigWithKey(SettingsType.EMAIL_CONFIGURATION.value());
SmtpSettings storedAndEncrypted =
JsonUtils.convertValue(stored.getConfigValue(), SmtpSettings.class);
assertTrue(Fernet.isTokenized(storedAndEncrypted.getPassword()));
assertEquals(
config.getSmtpSettings().getPassword(),
Fernet.getInstance().decryptIfApplies(storedAndEncrypted.getPassword()));
}
@Test
void testSystemConfigsUpdate(TestInfo test) throws HttpResponseException {
// Test Email Config
SmtpSettings smtpSettings = config.getSmtpSettings();
// Update a few Email fields
smtpSettings.setUsername(test.getDisplayName());
smtpSettings.setEmailingEntity(test.getDisplayName());
updateSystemConfig(
new Settings()
.withConfigType(SettingsType.EMAIL_CONFIGURATION)
.withConfigValue(smtpSettings));
SmtpSettings updateEmailSettings =
JsonUtils.convertValue(
getSystemConfig(SettingsType.EMAIL_CONFIGURATION).getConfigValue(), SmtpSettings.class);
assertEquals(updateEmailSettings.getUsername(), test.getDisplayName());
assertEquals(updateEmailSettings.getEmailingEntity(), test.getDisplayName());
// Test Custom Logo Update and theme preference
UiThemePreference updateConfigReq =
new UiThemePreference()
@ -352,45 +307,13 @@ public class SystemResourceTest extends OpenMetadataApplicationTest {
@Test
void testDefaultSettingsInitialization() throws HttpResponseException {
SettingsCache.initialize(config);
Settings emailSettings = getSystemConfig(SettingsType.EMAIL_CONFIGURATION);
Settings uiThemeSettings = getSystemConfig(SettingsType.CUSTOM_UI_THEME_PREFERENCE);
SmtpSettings smtpSettings =
JsonUtils.convertValue(emailSettings.getConfigValue(), SmtpSettings.class);
assertEquals(config.getSmtpSettings().getUsername(), smtpSettings.getUsername());
assertEquals(config.getSmtpSettings().getEmailingEntity(), smtpSettings.getEmailingEntity());
UiThemePreference uiThemePreference =
JsonUtils.convertValue(uiThemeSettings.getConfigValue(), UiThemePreference.class);
assertEquals("", uiThemePreference.getCustomTheme().getPrimaryColor());
assertEquals("", uiThemePreference.getCustomLogoConfig().getCustomLogoUrlPath());
}
@Test
void testEmailConfigurationSettings() throws HttpResponseException {
Settings emailSettings = getSystemConfig(SettingsType.EMAIL_CONFIGURATION);
SmtpSettings smtpSettings =
JsonUtils.convertValue(emailSettings.getConfigValue(), SmtpSettings.class);
SmtpSettings expectedSmtpSettings = config.getSmtpSettings();
expectedSmtpSettings.setPassword(
smtpSettings.getPassword()); // Password is encrypted, so we use the stored one
assertEquals(expectedSmtpSettings, smtpSettings);
smtpSettings.setUsername("updatedUsername");
smtpSettings.setEmailingEntity("updatedEntity");
Settings updatedEmailSettings =
new Settings()
.withConfigType(SettingsType.EMAIL_CONFIGURATION)
.withConfigValue(smtpSettings);
updateSystemConfig(updatedEmailSettings);
Settings updatedSettings = getSystemConfig(SettingsType.EMAIL_CONFIGURATION);
SmtpSettings updatedSmtpSettings =
JsonUtils.convertValue(updatedSettings.getConfigValue(), SmtpSettings.class);
assertEquals("updatedUsername", updatedSmtpSettings.getUsername());
assertEquals("updatedEntity", updatedSmtpSettings.getEmailingEntity());
}
@Order(3)
@Test
void testUiThemePreferenceSettings() throws HttpResponseException {

View File

@ -210,18 +210,6 @@ pipelineServiceClientConfiguration:
truststorePath: ""
truststorePassword: ""
email:
enableSmtpServer : false
emailingEntity: "openmetadata"
supportUrl: "http://localhost:8585"
openMetadataUrl: "http://localhost:8585"
senderMail: "test@openmetadata.org"
serverEndpoint: "test.smtp.com"
serverPort: "584"
username: "test"
password: "test"
transportationStrategy: "SMTP_TLS"
fernetConfiguration:
fernetKey: ${FERNET_KEY:-ihZpp5gmmDvVsgoOG6OVivKWwC9vd5JQ}

View File

@ -0,0 +1,15 @@
{
"$id": "https://open-metadata.org/schema/entity/configuration/openMetadataBaseUrlConfiguration.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OpenMetadataBaseUrlConfiguration",
"description": "This schema defines the OpenMetadata base URL configuration",
"type": "object",
"javaType": "org.openmetadata.schema.api.configuration.OpenMetadataBaseUrlConfiguration",
"properties": {
"openMetadataUrl": {
"description": "OpenMetadata Server Endpoint",
"type": "string"
}
},
"additionalProperties": false
}

View File

@ -21,10 +21,6 @@
"type": "boolean",
"default": false
},
"openMetadataUrl": {
"description": "Openmetadata Server Endpoint",
"type": "string"
},
"senderMail": {
"description": "Mail of the sender",
"type": "string"
@ -60,5 +56,5 @@
}
},
"additionalProperties": false,
"required": ["serverEndpoint", "serverPort", "senderMail", "openMetadataUrl"]
"required": ["serverEndpoint", "serverPort", "senderMail"]
}

View File

@ -23,6 +23,7 @@
"sandboxModeEnabled",
"slackChat",
"emailConfiguration",
"openMetadataBaseUrlConfiguration",
"customUiThemePreference",
"loginConfiguration",
"slackAppConfiguration",
@ -71,6 +72,9 @@
{
"$ref": "../email/smtpSettings.json"
},
{
"$ref": "../configuration/openMetadataBaseUrlConfiguration.json"
},
{
"$ref": "../configuration/slackAppConfiguration.json"
},

View File

@ -87,6 +87,7 @@ export enum GlobalSettingOptions {
METRICS = 'metrics',
SEARCH_RBAC = 'search-rbac',
LINEAGE_CONFIG = 'lineageConfig',
OM_URL_CONFIG = 'om-url-config',
}
export const SETTINGS_OPTIONS_PATH = {
@ -209,6 +210,10 @@ export const SETTINGS_OPTIONS_PATH = {
GlobalSettingsMenuCategory.PREFERENCES,
`${GlobalSettingsMenuCategory.PREFERENCES}.${GlobalSettingOptions.LINEAGE_CONFIG}`,
],
[GlobalSettingOptions.OM_URL_CONFIG]: [
GlobalSettingsMenuCategory.PREFERENCES,
`${GlobalSettingsMenuCategory.PREFERENCES}.${GlobalSettingOptions.OM_URL_CONFIG}`,
],
};
export const SETTING_CUSTOM_PROPERTIES_PATH = {

View File

@ -0,0 +1,50 @@
/*
* Copyright 2025 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 { expect, test } from '@playwright/test';
import { GlobalSettingOptions } from '../../constant/settings';
import { redirectToHomePage, toastNotification } from '../../utils/common';
import { settingClick } from '../../utils/sidebar';
// use the admin user to login
test.use({ storageState: 'playwright/.auth/admin.json' });
test.describe('OM URL configuration', () => {
test.beforeEach(async ({ page }) => {
await redirectToHomePage(page);
await settingClick(page, GlobalSettingOptions.OM_URL_CONFIG);
});
test('update om url configuration should work', async ({ page }) => {
// Click the edit button
await page.click('[data-testid="edit-button"]');
// Update OM URL
await page.fill(
'[data-testid="open-metadata-url-input"]',
'http://localhost:8080'
);
const res = page.waitForResponse('/api/v1/system/settings');
await page.click('[data-testid="save-button"]');
await res;
await toastNotification(
page,
/OpenMetadata URL Configuration updated successfully./
);
await expect(page.locator('[data-testid="open-metadata-url"]')).toHaveText(
'http://localhost:8080'
);
});
});

View File

@ -27,13 +27,6 @@ $$
$$section
### OpenMetadata URL $(id="openMetadataUrl")
Url of the OpenMetadata Server, in case of Docker or K8s this needs to be the external Url used to access the UI.
$$
$$section
### Server Endpoint $(id="serverEndpoint")
Endpoint of the SMTP server (Ex. smtp.gmail.com)

View File

@ -0,0 +1,8 @@
# OpenMetadata Configuration
$$section
### OpenMetadata URL $(id="openMetadataUrl")
Defines the base URL for the OpenMetadata instance. The default value is typically set to http://localhost:8585.
$$

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#4A696F;" d="M341.495,341.492l48.581-73.615l-48.581-12.517c-6.364-19.092-17.185-37.126-32.459-52.4
c-15.063-15.063-32.882-26.095-52.4-32.459l-0.637,0.637l-59.188-2.334l-26.307,1.697c-19.517,6.364-37.337,17.396-52.4,32.459
l-78.646,78.646c-52.612,52.612-52.612,138.12,0,190.732c54.097,54.097,139.593,51.34,190.932,0l78.646-78.446
C324.312,378.616,335.132,360.585,341.495,341.492z M177.354,419.3c-23.761,23.761-61.734,23.125-84.859,0
c-23.336-23.336-23.336-61.523,0-84.859l78.009-77.809l42.642,42.217L256,340.854L177.354,419.3z"/>
<path style="fill:#384949;" d="M309.037,393.891l-78.646,78.446c-51.34,51.34-136.835,54.097-190.932,0L92.495,419.3
c23.125,23.125,61.098,23.761,84.859,0L256,340.855l-42.853-42.006l95.89-95.89c15.274,15.274,26.095,33.307,32.459,52.4
l48.581,12.517l-48.581,73.615C335.132,360.585,324.312,378.616,309.037,393.891z"/>
<path style="fill:#D2C5C2;" d="M415.11,436.321l-21.215-21.215c-5.863-5.863-5.863-15.352,0-21.215
c5.863-5.862,15.352-5.863,21.215,0l21.215,21.215c5.863,5.863,5.863,15.352,0,21.215
C430.461,442.184,420.973,442.184,415.11,436.321z"/>
<path style="fill:#DFD7D5;" d="M96.89,118.101L75.674,96.886c-5.863-5.863-5.863-15.352,0-21.214s15.352-5.863,21.214,0
l21.214,21.214c5.863,5.863,5.863,15.352,0,21.214S102.752,123.963,96.89,118.101z"/>
<path style="fill:#D2C5C2;" d="M444.363,306.464c2.144-8.008,10.369-12.752,18.376-10.608l28.984,7.769
c8.008,2.103,12.731,10.369,10.608,18.376c-2.144,8.008-10.369,12.752-18.376,10.608l-28.984-7.769
C447.016,322.711,442.217,314.519,444.363,306.464z"/>
<path style="fill:#DFD7D5;" d="M9.669,189.99c2.144-8.008,10.369-12.752,18.376-10.608l28.984,7.77
c7.977,2.092,12.741,10.359,10.608,18.376c-2.144,8.008-10.369,12.752-18.376,10.608l-28.984-7.77
C12.322,206.237,7.522,198.045,9.669,189.99z"/>
<path style="fill:#D2C5C2;" d="M303.629,491.719l-7.77-28.984c-2.144-8.008,2.6-16.232,10.608-18.376s16.222,2.569,18.376,10.608
l7.769,28.984c2.144,8.008-2.6,16.232-10.608,18.376C313.951,504.473,305.758,499.674,303.629,491.719z"/>
<path style="fill:#DFD7D5;" d="M187.155,57.026l-7.77-28.984c-2.144-8.008,2.6-16.232,10.608-18.376
c8.008-2.123,16.242,2.569,18.376,10.608l7.77,28.984c2.144,8.008-2.6,16.232-10.608,18.376
C197.477,69.778,189.285,64.979,187.155,57.026z"/>
<path style="fill:#FFD400;" d="M472.54,39.655c-52.612-52.612-138.108-52.825-190.932,0l-78.646,78.446
c-15.274,15.274-26.094,33.306-32.459,52.4c-9.335,28.004-9.334,58.128,0.001,86.132c6.364,19.092,17.184,37.127,32.458,52.401
c14.851,14.851,32.671,25.881,52.401,32.458l0.636-0.636c23.337-23.337,23.336-61.523,0-84.859s-23.336-61.523,0-84.859
l78.646-78.446c11.457-11.457,26.307-17.396,42.431-17.396c0.423-0.423,4.029-0.212,4.879,0.212
c11.456-0.001,26.517,6.151,37.549,17.184c23.336,23.336,23.337,61.522,0,84.859l-78.008,77.808c9.335,28.004,9.335,58.129,0,86.133
c19.304-6.576,37.55-17.608,52.4-32.459l78.646-78.446C525.154,177.974,525.152,92.267,472.54,39.655z"/>
<g>
<path style="fill:#FF9F00;" d="M256,340.854l-0.636,0.636c-19.729-6.576-37.551-17.607-52.401-32.458L256,255.995
C279.336,279.332,279.337,317.518,256,340.854z"/>
<path style="fill:#FF9F00;" d="M472.54,230.588l-78.646,78.446c-14.85,14.851-33.095,25.883-52.4,32.459
c9.335-28.004,9.335-58.129,0-86.133l78.008-77.808c23.337-23.337,23.336-61.523,0-84.859l53.037-53.037
C525.152,92.267,525.154,177.974,472.54,230.588z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -28,7 +28,9 @@ import AppearanceConfigSettingsPage from '../../pages/AppearanceConfigSettingsPa
import ApplicationPage from '../../pages/Application/ApplicationPage';
import BotsPageV1 from '../../pages/BotsPageV1/BotsPageV1.component';
import EditLoginConfiguration from '../../pages/Configuration/EditLoginConfiguration/EditLoginConfigurationPage';
import EditUrlConfigurationPage from '../../pages/Configuration/EditUrlConfiguration/EditUrlConfigurationPage';
import LoginConfigurationPage from '../../pages/Configuration/LoginConfigurationDetails/LoginConfigurationPage';
import UrlConfigurationPage from '../../pages/Configuration/UrlConfiguration/UrlConfigurationPage';
import { CustomPageSettings } from '../../pages/CustomPageSettings/CustomPageSettings';
import CustomPropertiesPageV1 from '../../pages/CustomPropertiesPageV1/CustomPropertiesPageV1';
import EditEmailConfigPage from '../../pages/EditEmailConfigPage/EditEmailConfigPage.component';
@ -103,6 +105,13 @@ const SettingsRouter = () => {
path={ROUTES.SETTINGS_EDIT_EMAIL_CONFIG}
/>
<AdminProtectedRoute
exact
component={EditUrlConfigurationPage}
hasPermission={false}
path={ROUTES.SETTINGS_OM_URL_CONFIG}
/>
<AdminProtectedRoute
exact
component={EditLoginConfiguration}
@ -269,6 +278,15 @@ const SettingsRouter = () => {
)}
/>
<AdminProtectedRoute
exact
component={UrlConfigurationPage}
path={getSettingPath(
GlobalSettingsMenuCategory.PREFERENCES,
GlobalSettingOptions.OM_URL_CONFIG
)}
/>
<AdminProtectedRoute
exact
component={PoliciesListPage}

View File

@ -69,15 +69,6 @@ function EmailConfigForm({
type="email"
/>
</Item>
<Item
label={t('label.open-metadata-url')}
name="openMetadataUrl"
rules={[{ required: true }]}>
<Input
data-testid="open-metadata-url-input"
id="root/openMetadataUrl-input"
/>
</Item>
<Item
label={t('label.server-endpoint')}
name="serverEndpoint"

View File

@ -33,7 +33,6 @@ const emailConfigValues = {
emailingEntity: 'OpenMetadata',
supportUrl: 'https://slack.open-metadata.org',
enableSmtpServer: false,
openMetadataUrl: 'http://localhost:3000/',
senderMail: 'test@gmail.com',
serverEndpoint: 'http://localhost:3000',
serverPort: 357,
@ -65,7 +64,6 @@ describe('Email Config Form Component', () => {
expect(screen.getByText('label.username')).toBeInTheDocument();
expect(screen.getByText('label.password')).toBeInTheDocument();
expect(screen.getByText('label.sender-email')).toBeInTheDocument();
expect(screen.getByText('label.open-metadata-url')).toBeInTheDocument();
expect(screen.getByText('label.server-endpoint')).toBeInTheDocument();
expect(screen.getByText('label.server-port')).toBeInTheDocument();
expect(screen.getByText('label.emailing-entity')).toBeInTheDocument();
@ -80,7 +78,6 @@ describe('Email Config Form Component', () => {
expect(screen.getByTestId('username-input')).toBeInTheDocument();
expect(screen.getByTestId('password-input')).toBeInTheDocument();
expect(screen.getByTestId('sender-email-input')).toBeInTheDocument();
expect(screen.getByTestId('open-metadata-url-input')).toBeInTheDocument();
expect(screen.getByTestId('server-endpoint-input')).toBeInTheDocument();
expect(screen.getByTestId('server-port-input')).toBeInTheDocument();
expect(screen.getByTestId('emailing-entity-input')).toBeInTheDocument();
@ -130,7 +127,6 @@ describe('Email Config Form Component', () => {
emailConfigValues={{
username: 'test',
password: 'test',
openMetadataUrl: '',
senderMail: '',
serverEndpoint: '',
serverPort: 0,

View File

@ -77,4 +77,5 @@ export enum GlobalSettingOptions {
METRICS = 'metrics',
SEARCH_RBAC = 'search-rbac',
LINEAGE_CONFIG = 'lineageConfig',
OM_URL_CONFIG = 'om-url-config',
}

View File

@ -206,6 +206,12 @@ export const PAGE_HEADERS = {
header: i18n.t('label.lineage-config'),
subHeader: i18n.t('message.page-sub-header-for-lineage-config-setting'),
},
OM_URL_CONFIG: {
header: i18n.t('label.entity-configuration', {
entity: i18n.t('label.open-metadata-url'),
}),
subHeader: i18n.t('message.om-url-configuration-message'),
},
OM_HEALTH: {
header: i18n.t('label.health-check'),
subHeader: i18n.t('message.page-sub-header-for-om-health-configuration'),

View File

@ -262,6 +262,7 @@ export const ROUTES = {
EDIT_KPI: `/data-insights/kpi/edit-kpi/${PLACEHOLDER_ROUTE_FQN}`,
SETTINGS_EDIT_CUSTOM_LOGIN_CONFIG: `/settings/OpenMetadata/loginConfiguration/edit-custom-login-configuration`,
SETTINGS_OM_URL_CONFIG: `/settings/OpenMetadata/openMetadataBaseUrlConfiguration/edit-open-metadata-url-configuration`,
CUSTOMIZE_PAGE: `/customize-page/${PLACEHOLDER_ROUTE_FQN}/:pageFqn`,

View File

@ -149,5 +149,7 @@ export const addDBTIngestionGuide = [
export const EMAIL_CONFIG_SERVICE_CATEGORY = 'EmailConfiguration';
export const CUSTOM_LOGIN_CONFIG_SERVICE_CATEGORY = 'CustomLoginConfiguration';
export const OPENMETADATA_URL_CONFIG_SERVICE_CATEGORY =
'OpenMetadataUrlConfiguration';
export const CUSTOM_PROPERTY_CATEGORY = 'CustomProperty';
export const OPEN_METADATA = 'OpenMetadata';

View File

@ -0,0 +1,21 @@
/*
* Copyright 2025 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.
*/
/**
* This schema defines the OpenMetadata base URL configuration
*/
export interface OpenMetadataBaseURLConfiguration {
/**
* OpenMetadata Server Endpoint
*/
openMetadataUrl?: string;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2024 Collate.
* Copyright 2025 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
@ -10,9 +10,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
/**
* This schema defines the SMTP Settings for sending Email
*/
export interface SMTPSettings {
@ -24,10 +22,6 @@ export interface SMTPSettings {
* If this is enable password will details will be shared on mail
*/
enableSmtpServer?: boolean;
/**
* Openmetadata Server Endpoint
*/
openMetadataUrl: string;
/**
* Smtp Server Password
*/

View File

@ -445,6 +445,7 @@
"enter-property-value": "Geben Sie einen Wert für die Eigenschaft ein",
"enter-type-password": "{{type}}-Passwort eingeben",
"entity": "Entity",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "{{entity}}-Anzahl",
"entity-detail-plural": "Details von {{entity}}",
"entity-feed-plural": "Entitäts-Feeds",
@ -1774,6 +1775,7 @@
"not-followed-anything": "Du hast noch nichts abonniert.",
"notification-description": "Set up notifications to received real-time updates and timely alerts.",
"om-description": "Zentraler Metadatenspeicher, um Daten zu entdecken, zusammenzuarbeiten und die Datenqualität zu verbessern.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "Daten funktionieren am besten, wenn sie einen Eigentümer haben. Sieh dir die Datenvermögenswerte an, die du besitzt, und beanspruche ihren Besitz.",
"onboarding-explore-data-description": "Schau dir die beliebten Datenvermögenswerte in deiner Organisation an.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "Enter Property Value",
"enter-type-password": "Enter {{type}} Password",
"entity": "Entity",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "{{entity}} Count",
"entity-detail-plural": "{{entity}} Details",
"entity-feed-plural": "Entity feeds",
@ -1774,6 +1775,7 @@
"not-followed-anything": "Start Exploring! and Follow the Data Assets that interests you.",
"notification-description": "Set up notifications to received real-time updates and timely alerts.",
"om-description": "Centralized metadata store, to discover, collaborate and get your data right.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "Data works well when it is owned. Take a look at the data assets that you own and claim ownership.",
"onboarding-explore-data-description": "Look at the popular data assets in your organization.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "Ingrese el valor de la propiedad",
"enter-type-password": "Ingrese la contraseña de {{type}}",
"entity": "Entidad",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "Cantidad de {{entity}}",
"entity-detail-plural": "Detalles de {{entity}}",
"entity-feed-plural": "Feeds de entidad",
@ -1774,6 +1775,7 @@
"not-followed-anything": "Todavía no has seguido nada.",
"notification-description": "Configura notificaciones para recibir actualizaciones en tiempo real y alertas oportunas.",
"om-description": "Almacenamiento centralizado de metadatos para descubrir, colaborar y tener los datos correctos.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "Revisa los activos de datos que posees y reclama su propiedad.",
"onboarding-explore-data-description": "Sigue los activos de datos populares en tu organización.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "Entrer une valeur pour la propriété",
"enter-type-password": "Entrer un mot de passe {{type}}",
"entity": "Entity",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "Décompte de {{entity}}",
"entity-detail-plural": "Détails de {{entity}}",
"entity-feed-plural": "Flux de l'Entité",
@ -1774,6 +1775,7 @@
"not-followed-anything": "Vous n'avez encore rien suivi.",
"notification-description": "Paramétrez les notifications pour recevoir des mises à jour en temps réel ansi que des alertes.",
"om-description": "Entrepôt centralisé de métadonnées, découvrez, collaborez et assurez-vous que vos données sont correctes",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "Les données fonctionnent mieux lorsqu'elles sont possédées. Revoyez les actifs de données que vous possédez et revendiquez la propriété.",
"onboarding-explore-data-description": "Découvrez les actifs de données populaires dans votre organisation.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "Introducir o valor da propiedade",
"enter-type-password": "Introducir contrasinal de {{type}}",
"entity": "Entidade",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "Contador de {{entity}}",
"entity-detail-plural": "Detalles de {{entity}}",
"entity-feed-plural": "Fontes de entidade",
@ -1774,6 +1775,7 @@
"not-followed-anything": "Comeza a explorar! E segue os Activos de Datos que che interesen.",
"notification-description": "Configura notificacións para recibir actualizacións en tempo real e alertas oportunas.",
"om-description": "Repositorio centralizado de metadatos, para descubrir, colaborar e xestionar os teus datos.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Executa a inxestión manualmente.",
"onboarding-claim-ownership-description": "Os datos funcionan mellor cando teñen propietario. Bota un ollo aos activos de datos que posúes e reclama a propiedade.",
"onboarding-explore-data-description": "Mira os activos de datos populares na túa organización.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "הזן ערך נכס",
"enter-type-password": "הזן סיסמה עבור {{type}}",
"entity": "ישות",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "ספירת {{entity}}",
"entity-detail-plural": "פרטי {{entity}}",
"entity-feed-plural": "הזנות ישויות",
@ -1774,6 +1775,7 @@
"not-followed-anything": "אתה לא עוקב אחרי כלום עדיין.",
"notification-description": "Set up notifications to received real-time updates and timely alerts.",
"om-description": "אחסון מטה מרכזי, לגלוש, לשתף פעולה ולהבין את הנתונים שלך כראוי.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "הנתונים פועלים טוב כשהם משולטים עליהם. עיין בנכסי הנתונים שאתה בעל ותטריד את הבעלות.",
"onboarding-explore-data-description": "בדוק את נכסי הנתונים הפופולריים בארגונך.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "プロパティの値を入力",
"enter-type-password": "{{type}} のパスワードを入力",
"entity": "Entity",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "{{entity}}の数",
"entity-detail-plural": "{{entity}} details",
"entity-feed-plural": "Entity feeds",
@ -1774,6 +1775,7 @@
"not-followed-anything": "あなたはまだ何もフォローしていません。",
"notification-description": "Set up notifications to received real-time updates and timely alerts.",
"om-description": "Centralized metadata store, to discover, collaborate and get your data right.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "Data works well when it is owned. Take a look at the data assets that you own and claim ownership.",
"onboarding-explore-data-description": "あなたの組織で人気のデータアセットを見る。",

View File

@ -445,6 +445,7 @@
"enter-property-value": "गुणधर्म मूल्य प्रविष्ट करा",
"enter-type-password": "{{type}} पासवर्ड प्रविष्ट करा",
"entity": "घटक",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "{{entity}} संख्या",
"entity-detail-plural": "{{entity}} तपशील",
"entity-feed-plural": "घटक फीड्स",
@ -1774,6 +1775,7 @@
"not-followed-anything": "अन्वेषण सुरू करा! आणि तुम्हाला स्वारस्य असलेल्या डेटा ॲसेट्सचे अनुसरण करा.",
"notification-description": "रिअल-टाइम अद्यतने आणि वेळेवर सूचना प्राप्त करण्यासाठी सूचना सेट अप करा.",
"om-description": "केंद्रीकृत मेटाडेटा स्टोअर, शोधण्यासाठी, सहयोग करण्यासाठी आणि तुमचा डेटा योग्य मिळवण्यासाठी.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "डेटा मालकीचा असताना चांगला असतो. तुम्ही मालकीचे असलेले डेटा ॲसेट्स पाहा आणि मालकी हक्क दावा करा.",
"onboarding-explore-data-description": "तुमच्या संस्थेतील लोकप्रिय डेटा ॲसेट्स पहा.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "Eigenschapswaarde invoeren",
"enter-type-password": "{{type}}-wachtwoord invoeren",
"entity": "Entiteit",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "Aantal {{entity}}",
"entity-detail-plural": "{{entity}}-details",
"entity-feed-plural": "Entiteitsfeeds",
@ -1774,6 +1775,7 @@
"not-followed-anything": "Je hebt nog niets gevolgd.",
"notification-description": "Set up notifications to received real-time updates and timely alerts.",
"om-description": "Gecentraliseerde metadatastore, om data te ontdekken, samen te werken en op orde te brengen.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "Data is het meest bruikbaar als het een eigenaar heeft. Bekijk de data-assets waar je eigenaar van bent en claim het eigendom.",
"onboarding-explore-data-description": "Bekijk de meestgebruikte data-assets in jouw organisatie.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "مقدار ویژگی را وارد کنید",
"enter-type-password": "رمز عبور {{type}} را وارد کنید",
"entity": "نهاد",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "تعداد {{entity}}",
"entity-detail-plural": "جزئیات {{entity}}",
"entity-feed-plural": "فیدهای نهاد",
@ -1774,6 +1775,7 @@
"not-followed-anything": "شروع به کاوش کنید! و دارایی‌های داده‌ای که شما را علاقه‌مند می‌کند دنبال کنید.",
"notification-description": "اعلان‌ها را تنظیم کنید تا به‌روزرسانی‌های زمان واقعی و هشدارهای به موقع دریافت کنید.",
"om-description": "ذخیره متمرکز متادیتا، برای کشف، همکاری و درست کردن داده‌های شما.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "داده زمانی خوب عمل می‌کند که مالکیت داشته باشد. به دارایی‌های داده‌ای که شما مالکیت دارید نگاهی بیندازید و مالکیت آنها را برعهده بگیرید.",
"onboarding-explore-data-description": "به دارایی‌های داده‌ای محبوب در سازمان خود نگاهی بیندازید.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "Inserir Valor da Propriedade",
"enter-type-password": "Inserir Senha de {{type}}",
"entity": "Entidade",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "Contagem de {{entity}}",
"entity-detail-plural": "Detalhes de {{entity}}",
"entity-feed-plural": "Feeds de Entidade",
@ -1774,6 +1775,7 @@
"not-followed-anything": "Você ainda não seguiu nada.",
"notification-description": "Configure notificações para receber atualizações em tempo real e alertas.",
"om-description": "Armazenamento centralizado de metadados, para descobrir, colaborar e obter seus dados corretamente.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "Os dados funcionam bem quando são de propriedade. Dê uma olhada nos ativos de dados que você possui e reivindique a propriedade.",
"onboarding-explore-data-description": "Veja os ativos de dados populares em sua organização.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "Inserir Valor da Propriedade",
"enter-type-password": "Inserir Senha de {{type}}",
"entity": "Entidade",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "Contagem de {{entity}}",
"entity-detail-plural": "Detalhes de {{entity}}",
"entity-feed-plural": "Feeds de Entidade",
@ -1774,6 +1775,7 @@
"not-followed-anything": "Você ainda não seguiu nada.",
"notification-description": "Configure notificações para receber atualizações em tempo real e alertas.",
"om-description": "Armazenamento centralizado de metadados, para descobrir, colaborar e obter seus dados corretamente.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "Os dados funcionam bem quando são de propriedade. Dê uma olhada nos ativos de dados que você possui e reivindique a propriedade.",
"onboarding-explore-data-description": "Veja os ativos de dados populares em sua organização.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "Введите значение свойства",
"enter-type-password": "Введите {{type}} пароль",
"entity": "Entity",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "Количество \"{{entity}}\"",
"entity-detail-plural": "{{entity}} детали",
"entity-feed-plural": "Фиды объектов",
@ -1774,6 +1775,7 @@
"not-followed-anything": "Вы еще не подписаны ни на один объект.",
"notification-description": "Set up notifications to received real-time updates and timely alerts.",
"om-description": "Централизованное хранилище метаданных для обнаружения, совместной работы и правильной обработки ваших данных.",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "Данные работают хорошо, когда ими владеют. Взгляните на объекты данных, которыми вы владеете, и заявите о праве собственности.",
"onboarding-explore-data-description": "Посмотрите на популярные объекты данных в вашей организации.",

View File

@ -445,6 +445,7 @@
"enter-property-value": "ป้อนค่าของคุณสมบัติ",
"enter-type-password": "ป้อนรหัสผ่าน {{type}}",
"entity": "เอนทิตี",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "จำนวน {{entity}}",
"entity-detail-plural": "รายละเอียด {{entity}}",
"entity-feed-plural": "ฟีดเอนทิตี",
@ -1774,6 +1775,7 @@
"not-followed-anything": "เริ่มต้นสำรวจ! และติดตามสินทรัพย์ข้อมูลที่คุณสนใจ",
"notification-description": "ตั้งค่าการแจ้งเตือนเพื่อรับข้อมูลอัปเดตแบบเรียลไทม์และการแจ้งเตือนที่ตรงเวลา",
"om-description": "ที่จัดเก็บข้อมูลเมตาที่รวมศูนย์ เพื่อค้นหา, ร่วมมือ และรับข้อมูลที่ถูกต้อง",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "เรียกใช้งานการนำเข้าด้วยตนเอง",
"onboarding-claim-ownership-description": "ข้อมูลทำงานได้ดีเมื่อมีการเป็นเจ้าของ มาดูสินทรัพย์ข้อมูลที่คุณเป็นเจ้าของและรับสิทธิ์ความเป็นเจ้าของ",
"onboarding-explore-data-description": "ดูสินทรัพย์ข้อมูลที่เป็นที่นิยมในองค์กรของคุณ",

View File

@ -445,6 +445,7 @@
"enter-property-value": "输入属性值",
"enter-type-password": "输入{{type}}密码",
"entity": "实体",
"entity-configuration": "{{entity}} Configuration",
"entity-count": "{{entity}}计数",
"entity-detail-plural": "{{entity}}详情",
"entity-feed-plural": "实体信息流",
@ -1774,6 +1775,7 @@
"not-followed-anything": "尚未关注任何内容",
"notification-description": "设置通知以接收实时更新和及时警报",
"om-description": "统一的元数据存储平台, 更好地探索、协作和处理数据",
"om-url-configuration-message": "Configure the OpenMetadata URL Settings.",
"on-demand-description": "Run the ingestion manually.",
"onboarding-claim-ownership-description": "查看数据资产并声明所有权, 以更好的维护数据",
"onboarding-explore-data-description": "查看组织中热门的数据资产",

View File

@ -0,0 +1,203 @@
/*
* Copyright 2025 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, Col, Form, Input, Row } from 'antd';
import { AxiosError } from 'axios';
import React, { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
import Loader from '../../../components/common/Loader/Loader';
import ResizablePanels from '../../../components/common/ResizablePanels/ResizablePanels';
import ServiceDocPanel from '../../../components/common/ServiceDocPanel/ServiceDocPanel';
import TitleBreadcrumb from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component';
import { VALIDATION_MESSAGES } from '../../../constants/constants';
import {
GlobalSettingOptions,
GlobalSettingsMenuCategory,
} from '../../../constants/GlobalSettings.constants';
import {
OPENMETADATA_URL_CONFIG_SERVICE_CATEGORY,
OPEN_METADATA,
} from '../../../constants/service-guide.constant';
import { ServiceCategory } from '../../../enums/service.enum';
import { OpenMetadataBaseURLConfiguration } from '../../../generated/configuration/openMetadataBaseUrlConfiguration';
import { Settings, SettingType } from '../../../generated/settings/settings';
import {
getSettingsConfigFromConfigType,
updateSettingsConfig,
} from '../../../rest/settingConfigAPI';
import { getSettingPath } from '../../../utils/RouterUtils';
import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils';
const { Item } = Form;
const EditUrlConfigurationPage = () => {
const { t } = useTranslation();
const history = useHistory();
const [form] = Form.useForm<OpenMetadataBaseURLConfiguration>();
const [activeField, setActiveField] = useState<string>('');
const [loading, setLoading] = useState<boolean>(false);
const [updating, setUpdating] = useState<boolean>(false);
const fetchCustomLogoConfig = async () => {
try {
setLoading(true);
const { data } = await getSettingsConfigFromConfigType(
SettingType.OpenMetadataBaseURLConfiguration
);
form.setFieldsValue({ ...(data.config_value ?? {}) });
} catch (error) {
showErrorToast(error as AxiosError);
} finally {
setLoading(false);
}
};
const breadcrumb = useMemo(
() => [
{
name: t('label.setting-plural'),
url: getSettingPath(),
},
{
name: t('label.entity-configuration', {
entity: t('label.open-metadata-url'),
}),
url: getSettingPath(
GlobalSettingsMenuCategory.PREFERENCES,
GlobalSettingOptions.OM_URL_CONFIG
),
},
{
name: t('label.edit-entity', {
entity: t('label.entity-configuration', {
entity: t('label.open-metadata-url'),
}),
}),
url: '',
},
],
[]
);
const handleGoBack = () => history.goBack();
const handleSubmit = async (
configValues: OpenMetadataBaseURLConfiguration
) => {
try {
setUpdating(true);
const configData = {
config_type: SettingType.OpenMetadataBaseURLConfiguration,
config_value: configValues,
};
await updateSettingsConfig(configData as Settings);
showSuccessToast(
t('server.update-entity-success', {
entity: t('label.entity-configuration', {
entity: t('label.open-metadata-url'),
}),
})
);
handleGoBack();
} catch (error) {
showErrorToast(error as AxiosError);
} finally {
setUpdating(false);
}
};
useEffect(() => {
fetchCustomLogoConfig();
}, []);
const firstPanelChildren = (
<div className="max-width-md w-9/10 service-form-container">
<TitleBreadcrumb titleLinks={breadcrumb} />
<Form
className="m-t-md"
data-testid="custom-login-config-form"
form={form}
layout="vertical"
validateMessages={VALIDATION_MESSAGES}
onFinish={handleSubmit}
onFocus={(e) => {
e.preventDefault();
e.stopPropagation();
setActiveField(e.target.id);
}}>
<Item
label={t('label.open-metadata-url')}
name="openMetadataUrl"
rules={[{ required: true }]}>
<Input
data-testid="open-metadata-url-input"
id="root/openMetadataUrl-input"
/>
</Item>
<Row justify="end">
<Col>
<Button
data-testid="cancel-button"
type="link"
onClick={handleGoBack}>
{t('label.cancel')}
</Button>
</Col>
<Col>
<Button
data-testid="save-button"
htmlType="submit"
loading={updating}
type="primary">
{t('label.save')}
</Button>
</Col>
</Row>
</Form>
</div>
);
const secondPanelChildren = (
<ServiceDocPanel
activeField={activeField}
serviceName={OPENMETADATA_URL_CONFIG_SERVICE_CATEGORY}
serviceType={OPEN_METADATA as ServiceCategory}
/>
);
if (loading) {
return <Loader />;
}
return (
<ResizablePanels
className="content-height-with-resizable-panel"
firstPanel={{
children: firstPanelChildren,
minWidth: 700,
flex: 0.7,
className: 'content-resizable-panel-container',
}}
pageTitle={t('label.edit-entity', { entity: t('label.service') })}
secondPanel={{
children: secondPanelChildren,
className: 'service-doc-panel content-resizable-panel-container',
minWidth: 400,
flex: 0.3,
}}
/>
);
};
export default EditUrlConfigurationPage;

View File

@ -0,0 +1,122 @@
/*
* Copyright 2025 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 Icon from '@ant-design/icons';
import { Button, Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios';
import React, { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
import { ReactComponent as IconEdit } from '../../../assets/svg/edit-new.svg';
import Loader from '../../../components/common/Loader/Loader';
import TitleBreadcrumb from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component';
import { TitleBreadcrumbProps } from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.interface';
import PageHeader from '../../../components/PageHeader/PageHeader.component';
import PageLayoutV1 from '../../../components/PageLayoutV1/PageLayoutV1';
import { NO_DATA_PLACEHOLDER, ROUTES } from '../../../constants/constants';
import { GlobalSettingsMenuCategory } from '../../../constants/GlobalSettings.constants';
import { PAGE_HEADERS } from '../../../constants/PageHeaders.constant';
import { OpenMetadataBaseURLConfiguration } from '../../../generated/configuration/openMetadataBaseUrlConfiguration';
import { SettingType } from '../../../generated/settings/settings';
import { getSettingsConfigFromConfigType } from '../../../rest/settingConfigAPI';
import { getSettingPageEntityBreadCrumb } from '../../../utils/GlobalSettingsUtils';
import { showErrorToast } from '../../../utils/ToastUtils';
const UrlConfigurationPage = () => {
const { t } = useTranslation();
const history = useHistory();
const [loading, setLoading] = useState<boolean>(false);
const [urlConfig, setUrlConfig] =
useState<OpenMetadataBaseURLConfiguration>();
const breadcrumbs: TitleBreadcrumbProps['titleLinks'] = useMemo(
() =>
getSettingPageEntityBreadCrumb(
GlobalSettingsMenuCategory.PREFERENCES,
t('label.entity-configuration', {
entity: t('label.open-metadata-url'),
})
),
[]
);
const fetchUrlConfig = async () => {
try {
setLoading(true);
const { data } = await getSettingsConfigFromConfigType(
SettingType.OpenMetadataBaseURLConfiguration
);
setUrlConfig(data.config_value as OpenMetadataBaseURLConfiguration);
} catch (error) {
showErrorToast(error as AxiosError);
} finally {
setLoading(false);
}
};
const handleEditClick = () => {
history.push(ROUTES.SETTINGS_OM_URL_CONFIG);
};
useEffect(() => {
fetchUrlConfig();
}, []);
if (loading) {
return <Loader />;
}
return (
<PageLayoutV1 pageTitle={t('label.login')}>
<Row className="page-container" gutter={[0, 16]}>
<Col span={24}>
<TitleBreadcrumb titleLinks={breadcrumbs} />
</Col>
<Col span={24}>
<Row align="middle" justify="space-between">
<Col>
<PageHeader data={PAGE_HEADERS.OM_URL_CONFIG} />
</Col>
<Col>
<Button
data-testid="edit-button"
icon={<Icon component={IconEdit} size={12} />}
onClick={handleEditClick}>
{t('label.edit')}
</Button>
</Col>
</Row>
</Col>
<Col span={12}>
<Row align="middle">
<Col span={24}>
<Typography.Text className="m-0 text-grey-muted">
{t('label.open-metadata-url')}
</Typography.Text>
</Col>
<Col span={24}>
<Typography.Text data-testid="open-metadata-url">
{urlConfig?.openMetadataUrl
? urlConfig.openMetadataUrl
: NO_DATA_PLACEHOLDER}
</Typography.Text>
</Col>
</Row>
</Col>
</Row>
</PageLayoutV1>
);
};
export default UrlConfigurationPage;

View File

@ -28,6 +28,8 @@ import { ReactComponent as DashboardDataModelIcon } from '../assets/svg/ic-dashb
import { ReactComponent as DataProductIcon } from '../assets/svg/ic-data-product-colored.svg';
import { ReactComponent as SchemaIcon } from '../assets/svg/ic-database-schema-colored.svg';
import { ReactComponent as LineageIcon } from '../assets/svg/ic-lineage-config.svg';
import { ReactComponent as LinkIcon } from '../assets/svg/ic-url-link.svg';
import { ReactComponent as LoginIcon } from '../assets/svg/login-colored.svg';
import { ReactComponent as OpenMetadataIcon } from '../assets/svg/logo-monogram.svg';
import { ReactComponent as MessagingIcon } from '../assets/svg/messaging-colored.svg';
@ -358,6 +360,13 @@ class GlobalSettingsClassBase {
key: `${GlobalSettingsMenuCategory.PREFERENCES}.${GlobalSettingOptions.LINEAGE_CONFIG}`,
icon: LineageIcon,
},
{
label: t('label.open-metadata-url'),
description: t('message.om-url-configuration-message'),
isProtected: Boolean(isAdminUser),
key: `${GlobalSettingsMenuCategory.PREFERENCES}.${GlobalSettingOptions.OM_URL_CONFIG}`,
icon: LinkIcon,
},
],
},
{