All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.datarouter.clustersetting.web.browse.setting.ClusterSettingBrowseSettingHtml Maven / Gradle / Ivy

/*
 * Copyright © 2009 HotPads ([email protected])
 *
 * 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.
 */
package io.datarouter.clustersetting.web.browse.setting;

import static j2html.TagCreator.a;
import static j2html.TagCreator.div;
import static j2html.TagCreator.span;
import static j2html.TagCreator.strong;
import static j2html.TagCreator.td;

import java.util.List;
import java.util.Optional;

import io.datarouter.clustersetting.enums.ClusterSettingScope;
import io.datarouter.clustersetting.service.ClusterSettingService;
import io.datarouter.clustersetting.storage.clustersetting.ClusterSetting;
import io.datarouter.clustersetting.storage.clustersetting.DatarouterClusterSettingDao;
import io.datarouter.clustersetting.storage.clustersettinglog.DatarouterClusterSettingLogDao;
import io.datarouter.clustersetting.web.browse.ClusterSettingBrowseHandler.ClusterSettingBrowseHandlerParams;
import io.datarouter.clustersetting.web.browse.ClusterSettingBrowseHandler.ClusterSettingBrowseLinks;
import io.datarouter.clustersetting.web.browse.setting.CodeOverridesTool.CodeOverrideRow;
import io.datarouter.clustersetting.web.browse.setting.DatabaseOverridesTool.DatabaseOverrideRow;
import io.datarouter.clustersetting.web.browse.setting.TagOverridesTool.TagOverrideRow;
import io.datarouter.clustersetting.web.log.ClusterSettingLogHandler.ClusterSettingLogLinks;
import io.datarouter.clustersetting.web.override.ClusterSettingEditSource;
import io.datarouter.clustersetting.web.override.handler.ClusterSettingOverrideCreateHandler.ClusterSettingOverrideCreateLinks;
import io.datarouter.clustersetting.web.override.handler.ClusterSettingOverrideDeleteHandler.ClusterSettingOverrideDeleteLinks;
import io.datarouter.clustersetting.web.override.handler.ClusterSettingOverrideUpdateHandler.ClusterSettingOverrideUpdateLinks;
import io.datarouter.clustersetting.web.tag.ClusterSettingTagsHandler.ClusterSettingTagsLinks;
import io.datarouter.storage.setting.DatarouterSettingTag;
import io.datarouter.storage.setting.DefaultSettingValue;
import io.datarouter.storage.setting.cached.CachedSetting;
import io.datarouter.web.html.j2html.J2HtmlTable;
import j2html.tags.specialized.DivTag;
import j2html.tags.specialized.SpanTag;
import j2html.tags.specialized.TdTag;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

public record ClusterSettingBrowseSettingHtml(
		ClusterSettingBrowseLinks browseLinks,
		ClusterSettingLogLinks logLinks,
		ClusterSettingOverrideCreateLinks createOverrideLinks,
		ClusterSettingOverrideUpdateLinks updateOverrideLinks,
		ClusterSettingOverrideDeleteLinks deleteOverrideLinks,
		ClusterSettingTagsLinks tagsLinks,
		DatarouterClusterSettingDao settingDao,
		ClusterSettingService settingService,
		DatarouterClusterSettingLogDao logDao,
		ClusterSettingBrowseHandlerParams params){

	private static final String VALUE_STYLE = "background-color:#E5F8FF;word-break:break-all;";
	private static final String DEFAULT_VALUE_STYLE = "background-color:#E6E6E6;word-break:break-all;";

	public DivTag makeSettingDiv(CachedSetting setting){
		String name = setting.getName();
		DefaultSettingValue defaults = setting.getDefaultSettingValue();
		List overrideRows = CodeOverridesTool.makeOverrideRows(setting);
		List databaseSettings = settingDao.scanWithName(name).list();
		boolean isGlobalDefault = overrideRows.isEmpty() && databaseSettings.isEmpty();
		long logCount = logDao.countSettingLogs(name);
		var head = div();
		head.with(makeNameDiv(name).withClass("bg-light p-2"));
		var body = div()
				.withClass("p-2");
		body.with(makeValueDiv(setting, isGlobalDefault).withClass("my-1"));
		if(!isGlobalDefault){
			body.with(makeGlobalDefaultValueDiv(setting));
		}
		if(!overrideRows.isEmpty()){
			body.with(makeCodeOverridesDiv(overrideRows).withClass("my-3"));
		}
		if(defaults.hasTags()){
			body.with(makeTagOverridesDiv(setting).withClass("my-3"));
		}
		if(!databaseSettings.isEmpty()){
			body.with(makeDatabaseOverridesDiv(setting, databaseSettings).withClass("my-3"));
		}
		if(logCount > 0){
			body.with(makeSettingLogsDiv(name, logCount).withClass("my-2"));
		}
		return div(head, body)
				.withClass("border m-2");
	}

	private DivTag makeNameDiv(String name){
		var linkParams = new ClusterSettingBrowseHandlerParams()
				.withLocation(name)
				.withOptPartialName(params.partialName);
		String href = browseLinks.all(linkParams);
		var link = a(strong(shortName(name)))
				.withHref(href)
				.withStyle("font-size:1.1em;");
		var nameSpan = span(link);
		return div(nameSpan);
	}

	private DivTag makeValueDiv(
			CachedSetting setting,
			boolean isDefault){
		var addOverrideLink = a("Override")
				.withHref(createOverrideLinks.create(
						Optional.of(ClusterSettingEditSource.CODE),
						params.partialName,
						Optional.of(setting.getName())));
		String stringValue = setting.toStringValue();
		boolean inline = stringValue.length() <= 20;//show small values inline
		String title = inline ? "Value:" : "Value";
		String subtext = isDefault ? "default" : "on this server";
		var valueSpan = span(setting.toStringValue())
				.withClass("ml-1 p-1")
				.withStyle(VALUE_STYLE);
		var valueLine = div();
		valueLine.with(strong(title));
		if(inline){
			valueLine.with(valueSpan);
		}
		valueLine.with(span(String.format("(%s)", subtext)).withClass("ml-2").withStyle("color:gray;"));
		valueLine.with(span("-").withClass("mx-2"));
		valueLine.with(addOverrideLink);
		var content = div(valueLine);
		if(!inline){//put bigger values below
			content.with(div(valueSpan).withClass("mt-2"));
		}
		return content;
	}

	private DivTag makeGlobalDefaultValueDiv(CachedSetting setting){
		return div(
				span("Default: "),
				span(setting.toStringDefaultValue())
						.withClass("m-1 p-1")
						.withStyle(DEFAULT_VALUE_STYLE))
				.withClass("ml-1")
				.withStyle("font-size:.9em;");
	}

	private  DivTag makeCodeOverridesDiv(
			List rows){
		var headerDiv = div(makeSectionHeaderSpan("Code Overrides", rows.size()));
		var tableBuilder = new J2HtmlTable()
				.withClasses("table table-sm border");
		tableBuilder.withHtmlColumn("Winner", row -> makeActiveOrWinnerCell(row.winner()));
		tableBuilder.withHtmlColumn("Active", row -> makeActiveOrWinnerCell(row.active()));
		if(CodeOverrideRow.notEmpty(rows, CodeOverrideRow::environmentType)){
			tableBuilder.withColumn("Env Type", CodeOverrideRow::environmentType);
		}
		if(CodeOverrideRow.notEmpty(rows, CodeOverrideRow::environmentName)){
			tableBuilder.withColumn("Env Name", CodeOverrideRow::environmentName);
		}
		if(CodeOverrideRow.notEmpty(rows, CodeOverrideRow::environmentCategoryName)){
			tableBuilder.withColumn("Env Category", CodeOverrideRow::environmentCategoryName);
		}
		if(CodeOverrideRow.notEmpty(rows, CodeOverrideRow::serverType)){
			tableBuilder.withColumn("Server Type", CodeOverrideRow::serverType);
		}
		if(CodeOverrideRow.notEmpty(rows, CodeOverrideRow::serverName)){
			tableBuilder.withColumn("Server Name", CodeOverrideRow::serverName);
		}
		tableBuilder.withHtmlColumn("Value", row -> makeValueCell(row.value()));
		var tableDiv = div(tableBuilder.build(rows));
		var bodyDiv = div(
				tableDiv)
				.withStyle("font-size:.9em;");
		return div(
				headerDiv,
				bodyDiv);
	}

	private DivTag makeTagOverridesDiv(CachedSetting setting){
		List rows = TagOverridesTool.makeRows(setting);
		var editTagsLink = a("Edit Tags")
				.withHref(tagsLinks.tags());
		var header = div(
				makeSectionHeaderSpan("Tag Overrides", rows.size()),
				span("-").withClass("mx-2"),
				editTagsLink);
		var table = new J2HtmlTable()
				.withClasses("table table-sm border")
				.withHtmlColumn("Active", row -> makeActiveOrWinnerCell(row.active()))
				.withColumn("Tag", TagOverrideRow::tag, DatarouterSettingTag::getPersistentString)
				.build(rows);
		var tableDiv = div(table)
				.withStyle("font-size:.9em;");
		return div(
				header,
				tableDiv);
	}

	private DivTag makeDatabaseOverridesDiv(
			CachedSetting setting,
			List dbSettings){
		Optional mostSpecificSetting = settingService.getMostSpecificClusterSetting(dbSettings);
		List rows = DatabaseOverridesTool.makeRows(setting, dbSettings, mostSpecificSetting);
		var addOverrideLink = a("Add")
				.withHref(createOverrideLinks.create(
						Optional.of(ClusterSettingEditSource.CODE),
						params.partialName,
						Optional.of(setting.getName())));
		var header = div(
				makeSectionHeaderSpan("Database Overrides", rows.size()),
				span("-").withClass("mx-2"),
				addOverrideLink);
		var tableBuilder = new J2HtmlTable()
				.withClasses("table table-sm border");
		tableBuilder.withHtmlColumn("Winner", row -> makeActiveOrWinnerCell(row.winner()));
		tableBuilder.withHtmlColumn("Active", row -> makeActiveOrWinnerCell(row.active()));
		tableBuilder.withColumn("Scope", DatabaseOverrideRow::scope, scope -> scope.display);
		if(DatabaseOverrideRow.anyServerType(rows)){
			tableBuilder.withColumn("Server Type", DatabaseOverrideRow::serverType);
		}
		if(DatabaseOverrideRow.notEmpty(rows, DatabaseOverrideRow::serverName)){
			tableBuilder.withColumn("Server Name", DatabaseOverrideRow::serverName);
		}
		tableBuilder.withHtmlColumn("Value", row -> makeValueCell(row.value()));
		tableBuilder.withHtmlColumn("Edit", this::makeEditDatabaseOverrideCell);
		tableBuilder.withHtmlColumn("X", this::makeDeleteDatabaseOverrideCell);
		var tableDiv = div(tableBuilder.build(rows))
				.withStyle("font-size:.9em;");
		var div = div(header);
		if(!rows.isEmpty()){
			div.with(tableDiv);
		}
		return div;
	}

	private DivTag makeSettingLogsDiv(String settingName, long logCount){
		var logLink = a("View")
				.withHref(logLinks.setting(settingName));
		return div(
				makeSectionHeaderSpan("Logs", logCount),
				span("-").withClass("mx-2"),
				logLink);
	}

	/*---------- cells ------------*/

	private TdTag makeActiveOrWinnerCell(boolean active){
		String marginClass = "ml-2";
		var content = active
				? strong("Yes")
						.withClass(marginClass)
						.withStyle("color:limegreen;")
				: span("No")
						.withClass(marginClass)
						.withStyle("color:salmon;");
		return td(content)
				.withStyle("width:50px;");
	}

	private TdTag makeValueCell(String value){
		return td(value)
				.withStyle("width:250px;word-break:break-all;");
	}

	private TdTag makeEditDatabaseOverrideCell(DatabaseOverrideRow row){
		Optional optServerType = ClusterSettingScope.SERVER_TYPE == row.scope()
				? Optional.of(row.serverType())
				: Optional.empty();
		Optional optServerName = ClusterSettingScope.SERVER_NAME == row.scope()
				? Optional.of(row.serverName())
				: Optional.empty();
		String href = updateOverrideLinks.update(
				Optional.of(ClusterSettingEditSource.CODE),
				params.partialName,
				row.name(),
				optServerType,
				optServerName);
		var deleteOverrideLink = a("edit")
				.withHref(href);
		return td(deleteOverrideLink)
				.withStyle("width:50px;");
	}

	private TdTag makeDeleteDatabaseOverrideCell(DatabaseOverrideRow row){
		Optional optServerType = ClusterSettingScope.SERVER_TYPE == row.scope()
				? Optional.of(row.serverType())
				: Optional.empty();
		Optional optServerName = ClusterSettingScope.SERVER_NAME == row.scope()
				? Optional.of(row.serverName())
				: Optional.empty();
		String href = deleteOverrideLinks.delete(
				Optional.of(ClusterSettingEditSource.CODE),
				params.location,
				params.partialName,
				row.name(),
				optServerType,
				optServerName);
		var deleteOverrideLink = a("X")
				.withTitle("Delete")
				.withHref(href);
		return td(deleteOverrideLink)
				.withStyle("width:30px;");
	}

	/*--------- helper ------------*/

	private SpanTag makeSectionHeaderSpan(String name, long count){
		return span(
				strong(name),
				span(String.format("(%s)", count))
						.withStyle("color:gray;font-size:1em;"));
	}

	private String shortName(String settingName){
		int splitAt = settingName.lastIndexOf('.') + 1;
		return settingName.substring(splitAt, settingName.length());
	}

	@Singleton
	public static class ClusterSettingBrowseSettingHtmlFactory{
		@Inject
		private ClusterSettingBrowseLinks browseLinks;
		@Inject
		private ClusterSettingLogLinks logLinks;
		@Inject
		private ClusterSettingOverrideCreateLinks createOverrideLinks;
		@Inject
		private ClusterSettingOverrideUpdateLinks updateOverrideLinks;
		@Inject
		private ClusterSettingOverrideDeleteLinks deleteOverrideLinks;
		@Inject
		private ClusterSettingTagsLinks tagsLinks;
		@Inject
		private DatarouterClusterSettingDao settingDao;
		@Inject
		private ClusterSettingService settingService;
		@Inject
		private DatarouterClusterSettingLogDao logDao;

		public ClusterSettingBrowseSettingHtml create(ClusterSettingBrowseHandlerParams params){
			return new ClusterSettingBrowseSettingHtml(
					browseLinks,
					logLinks,
					createOverrideLinks,
					updateOverrideLinks,
					deleteOverrideLinks,
					tagsLinks,
					settingDao,
					settingService,
					logDao,
					params);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy