chore: complimentary pr for CD migration changes (#35876)
## Description > CE changes for CD migration on EE pr: https://github.com/appsmithorg/appsmith-ee/pull/4927 ## Automation /ok-to-test tags="@tag.Git" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/10599263403> > Commit: ef94bff3b0d12db1a5003a78ce8ddfeabbb3c87d > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10599263403&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Git` > Spec: > <hr>Wed, 28 Aug 2024 15:23:46 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new field for tracking the continuous deployment migration version in application metadata. - Enhanced Git artifact management with additional metadata for improved deployment processes. - **Bug Fixes** - Resolved issues related to application versioning and deployment tracking. - **Refactor** - Substantial restructuring of the Application class for improved maintainability and extensibility. - Simplified structure of GitArtifactMetadata, enhancing functionality and clarity. - **Tests** - Expanded equality tests for new entities related to the Application class, ensuring proper validation of equality logic. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
db3f35691d
commit
a36b45de60
|
|
@ -1,36 +1,16 @@
|
||||||
package com.appsmith.server.domains;
|
package com.appsmith.server.domains;
|
||||||
|
|
||||||
import com.appsmith.external.models.BaseDomain;
|
import com.appsmith.server.domains.ce.ApplicationCE;
|
||||||
import com.appsmith.external.views.Git;
|
|
||||||
import com.appsmith.external.views.Views;
|
|
||||||
import com.appsmith.server.constants.ArtifactType;
|
|
||||||
import com.appsmith.server.dtos.CustomJSLibContextDTO;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonView;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.experimental.FieldNameConstants;
|
import lombok.experimental.FieldNameConstants;
|
||||||
import org.springframework.data.annotation.Transient;
|
|
||||||
import org.springframework.data.mongodb.core.mapping.Document;
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static com.appsmith.external.helpers.StringUtils.dotted;
|
|
||||||
import static com.appsmith.server.constants.ResourceModes.EDIT;
|
|
||||||
import static com.appsmith.server.constants.ResourceModes.VIEW;
|
|
||||||
import static com.appsmith.server.helpers.DateUtils.ISO_FORMATTER;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
|
@ -38,349 +18,20 @@ import static com.appsmith.server.helpers.DateUtils.ISO_FORMATTER;
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Document
|
@Document
|
||||||
@FieldNameConstants
|
@FieldNameConstants
|
||||||
public class Application extends BaseDomain implements Artifact {
|
public class Application extends ApplicationCE implements Artifact {
|
||||||
|
|
||||||
@NotNull @JsonView(Views.Public.class)
|
|
||||||
String name;
|
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String workspaceId;
|
|
||||||
|
|
||||||
// TODO: remove default values from application
|
|
||||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
|
||||||
@Deprecated(forRemoval = true)
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Boolean isPublic = false;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
List<ApplicationPage> pages;
|
|
||||||
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
List<ApplicationPage> publishedPages;
|
|
||||||
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
@Transient
|
|
||||||
Boolean viewMode = false;
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
boolean appIsExample = false;
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
long unreadCommentThreads;
|
|
||||||
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
String clonedFromApplicationId;
|
|
||||||
|
|
||||||
@JsonView({Views.Internal.class, Git.class})
|
|
||||||
ApplicationDetail unpublishedApplicationDetail;
|
|
||||||
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
ApplicationDetail publishedApplicationDetail;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
String color;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
String icon;
|
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
private String slug;
|
|
||||||
|
|
||||||
@JsonView({Views.Internal.class, Git.class})
|
|
||||||
AppLayout unpublishedAppLayout;
|
|
||||||
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
AppLayout publishedAppLayout;
|
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Set<CustomJSLibContextDTO> unpublishedCustomJSLibs;
|
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Set<CustomJSLibContextDTO> publishedCustomJSLibs;
|
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
GitArtifactMetadata gitApplicationMetadata;
|
|
||||||
|
|
||||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Instant lastDeployedAt; // when this application was last deployed
|
|
||||||
|
|
||||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
Integer evaluationVersion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* applicationVersion will be used when we've a breaking change in application, and it's not possible to write a
|
|
||||||
* migration. User need to update the application manually.
|
|
||||||
* In such cases, we can use this field to determine whether we need to notify user about that breaking change
|
|
||||||
* so that they can update their application.
|
|
||||||
* Once updated, we should set applicationVersion to latest version as well.
|
|
||||||
*/
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
Integer applicationVersion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changing name, change in pages, widgets and datasources will set lastEditedAt.
|
|
||||||
* Other activities e.g. changing policy will not change this property.
|
|
||||||
* We're adding JsonIgnore here because it'll be exposed as modifiedAt to keep it backward compatible
|
|
||||||
*/
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
Instant lastEditedAt;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
EmbedSetting embedSetting;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
Boolean collapseInvisibleWidgets;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Earlier this was returning value of the updatedAt property in the base domain.
|
|
||||||
* As this property is modified by the framework when there is any change in domain,
|
|
||||||
* a new property lastEditedAt has been added to track the edit actions from users.
|
|
||||||
* This method exposes that property.
|
|
||||||
*
|
|
||||||
* @return updated time as a string
|
|
||||||
*/
|
|
||||||
@JsonProperty(value = "modifiedAt", access = JsonProperty.Access.READ_ONLY)
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
public String getLastUpdateTime() {
|
|
||||||
if (lastEditedAt != null) {
|
|
||||||
return ISO_FORMATTER.format(lastEditedAt);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
public String getLastDeployedAt() {
|
|
||||||
if (lastDeployedAt != null) {
|
|
||||||
return ISO_FORMATTER.format(lastDeployedAt);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Boolean forkingEnabled;
|
|
||||||
|
|
||||||
// Field to convey if the application is updated by the user
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Boolean isManualUpdate;
|
|
||||||
|
|
||||||
// Field to convey if the application is modified from the DB migration
|
|
||||||
@Transient
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Boolean isAutoUpdate;
|
|
||||||
|
|
||||||
// To convey current schema version for client and server. This will be used to check if we run the migration
|
|
||||||
// between 2 commits if the application is connected to git
|
|
||||||
@JsonView({Views.Internal.class, Git.class})
|
|
||||||
Integer clientSchemaVersion;
|
|
||||||
|
|
||||||
@JsonView({Views.Internal.class, Git.class})
|
|
||||||
Integer serverSchemaVersion;
|
|
||||||
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
String publishedModeThemeId;
|
|
||||||
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
String editModeThemeId;
|
|
||||||
|
|
||||||
// TODO Temporary provision for exporting the application with datasource configuration for the sample/template apps
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Boolean exportWithConfiguration;
|
|
||||||
|
|
||||||
// forkWithConfiguration represents whether credentials are shared or not while forking an app
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Boolean forkWithConfiguration;
|
|
||||||
|
|
||||||
// isCommunityTemplate represents whether this application has been published as a community template
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Boolean isCommunityTemplate;
|
|
||||||
|
|
||||||
/* Template title of the template from which this app was forked, if any */
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String forkedFromTemplateTitle;
|
|
||||||
|
|
||||||
// This constructor is used during clone application. It only deeply copies selected fields. The rest are either
|
// This constructor is used during clone application. It only deeply copies selected fields. The rest are either
|
||||||
// initialized newly or is left up to the calling function to set.
|
// initialized newly or is left up to the calling function to set.
|
||||||
public Application(Application application) {
|
public Application(Application application) {
|
||||||
super();
|
super(application);
|
||||||
this.workspaceId = application.getWorkspaceId();
|
|
||||||
this.pages = new ArrayList<>();
|
|
||||||
this.publishedPages = new ArrayList<>();
|
|
||||||
this.clonedFromApplicationId = application.getId();
|
|
||||||
this.color = application.getColor();
|
|
||||||
this.icon = application.getIcon();
|
|
||||||
this.unpublishedAppLayout = application.getUnpublishedAppLayout() == null
|
|
||||||
? null
|
|
||||||
: new AppLayout(application.getUnpublishedAppLayout().type);
|
|
||||||
this.publishedAppLayout = application.getPublishedAppLayout() == null
|
|
||||||
? null
|
|
||||||
: new AppLayout(application.getPublishedAppLayout().type);
|
|
||||||
this.setUnpublishedApplicationDetail(new ApplicationDetail());
|
|
||||||
this.setPublishedApplicationDetail(new ApplicationDetail());
|
|
||||||
if (application.getUnpublishedApplicationDetail() == null) {
|
|
||||||
application.setUnpublishedApplicationDetail(new ApplicationDetail());
|
|
||||||
}
|
|
||||||
if (application.getPublishedApplicationDetail() == null) {
|
|
||||||
application.setPublishedApplicationDetail(new ApplicationDetail());
|
|
||||||
}
|
|
||||||
AppPositioning unpublishedAppPositioning =
|
|
||||||
application.getUnpublishedApplicationDetail().getAppPositioning() == null
|
|
||||||
? null
|
|
||||||
: new AppPositioning(
|
|
||||||
application.getUnpublishedApplicationDetail().getAppPositioning().type);
|
|
||||||
this.getUnpublishedApplicationDetail().setAppPositioning(unpublishedAppPositioning);
|
|
||||||
AppPositioning publishedAppPositioning =
|
|
||||||
application.getPublishedApplicationDetail().getAppPositioning() == null
|
|
||||||
? null
|
|
||||||
: new AppPositioning(
|
|
||||||
application.getPublishedApplicationDetail().getAppPositioning().type);
|
|
||||||
this.getPublishedApplicationDetail().setAppPositioning(publishedAppPositioning);
|
|
||||||
this.getUnpublishedApplicationDetail()
|
|
||||||
.setNavigationSetting(
|
|
||||||
application.getUnpublishedApplicationDetail().getNavigationSetting() == null
|
|
||||||
? null
|
|
||||||
: new NavigationSetting());
|
|
||||||
this.getPublishedApplicationDetail()
|
|
||||||
.setNavigationSetting(
|
|
||||||
application.getPublishedApplicationDetail().getNavigationSetting() == null
|
|
||||||
? null
|
|
||||||
: new NavigationSetting());
|
|
||||||
this.getUnpublishedApplicationDetail()
|
|
||||||
.setThemeSetting(
|
|
||||||
application.getUnpublishedApplicationDetail().getThemeSetting() == null
|
|
||||||
? null
|
|
||||||
: new ThemeSetting());
|
|
||||||
this.getPublishedApplicationDetail()
|
|
||||||
.setThemeSetting(
|
|
||||||
application.getPublishedApplicationDetail().getThemeSetting() == null
|
|
||||||
? null
|
|
||||||
: new ThemeSetting());
|
|
||||||
this.unpublishedCustomJSLibs = application.getUnpublishedCustomJSLibs();
|
|
||||||
this.collapseInvisibleWidgets = application.getCollapseInvisibleWidgets();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exportApplicationPages(final Map<String, String> pageIdToNameMap) {
|
|
||||||
for (ApplicationPage applicationPage : this.getPages()) {
|
|
||||||
applicationPage.setId(pageIdToNameMap.get(applicationPage.getId() + EDIT));
|
|
||||||
applicationPage.setDefaultPageId(null);
|
|
||||||
}
|
|
||||||
for (ApplicationPage applicationPage : this.getPublishedPages()) {
|
|
||||||
applicationPage.setId(pageIdToNameMap.get(applicationPage.getId() + VIEW));
|
|
||||||
applicationPage.setDefaultPageId(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getBaseId() {
|
|
||||||
if (this.getGitArtifactMetadata() != null
|
|
||||||
&& StringUtils.hasLength(this.getGitArtifactMetadata().getDefaultArtifactId())) {
|
|
||||||
return this.getGitArtifactMetadata().getDefaultArtifactId();
|
|
||||||
}
|
|
||||||
return Artifact.super.getBaseId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
@Override
|
|
||||||
public GitArtifactMetadata getGitArtifactMetadata() {
|
|
||||||
return this.gitApplicationMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
@Override
|
|
||||||
public void setGitArtifactMetadata(GitArtifactMetadata gitArtifactMetadata) {
|
|
||||||
this.gitApplicationMetadata = gitArtifactMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUnpublishedThemeId() {
|
|
||||||
return this.getEditModeThemeId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUnpublishedThemeId(String themeId) {
|
|
||||||
this.setEditModeThemeId(themeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPublishedThemeId() {
|
|
||||||
return this.getPublishedModeThemeId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPublishedThemeId(String themeId) {
|
|
||||||
this.setPublishedModeThemeId(themeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sanitiseToExportDBObject() {
|
|
||||||
this.setWorkspaceId(null);
|
|
||||||
this.setModifiedBy(null);
|
|
||||||
this.setCreatedBy(null);
|
|
||||||
this.setLastDeployedAt(null);
|
|
||||||
this.setLastEditedAt(null);
|
|
||||||
this.setGitApplicationMetadata(null);
|
|
||||||
this.setEditModeThemeId(null);
|
|
||||||
this.setPublishedModeThemeId(null);
|
|
||||||
this.setClientSchemaVersion(null);
|
|
||||||
this.setServerSchemaVersion(null);
|
|
||||||
this.setIsManualUpdate(false);
|
|
||||||
this.setPublishedCustomJSLibs(new HashSet<>());
|
|
||||||
this.setExportWithConfiguration(null);
|
|
||||||
this.setForkWithConfiguration(null);
|
|
||||||
this.setForkingEnabled(null);
|
|
||||||
super.sanitiseToExportDBObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ApplicationPage> getPages() {
|
|
||||||
return Boolean.TRUE.equals(viewMode) ? publishedPages : pages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AppLayout getAppLayout() {
|
|
||||||
return Boolean.TRUE.equals(viewMode) ? publishedAppLayout : unpublishedAppLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAppLayout(AppLayout appLayout) {
|
|
||||||
if (Boolean.TRUE.equals(viewMode)) {
|
|
||||||
publishedAppLayout = appLayout;
|
|
||||||
} else {
|
|
||||||
unpublishedAppLayout = appLayout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApplicationDetail getApplicationDetail() {
|
|
||||||
return Boolean.TRUE.equals(viewMode) ? publishedApplicationDetail : unpublishedApplicationDetail;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setApplicationDetail(ApplicationDetail applicationDetail) {
|
|
||||||
if (Boolean.TRUE.equals(viewMode)) {
|
|
||||||
publishedApplicationDetail = applicationDetail;
|
|
||||||
} else {
|
|
||||||
unpublishedApplicationDetail = applicationDetail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@JsonView({Views.Internal.class})
|
|
||||||
public ArtifactType getArtifactType() {
|
|
||||||
return ArtifactType.APPLICATION;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
public static class AppLayout extends AppLayoutCE implements Serializable {
|
||||||
public static class AppLayout implements Serializable {
|
public AppLayout(AppLayout.Type type) {
|
||||||
@JsonView({Views.Public.class, Git.class})
|
super(type);
|
||||||
Type type;
|
|
||||||
|
|
||||||
public enum Type {
|
|
||||||
DESKTOP,
|
|
||||||
TABLET_LARGE,
|
|
||||||
TABLET,
|
|
||||||
MOBILE,
|
|
||||||
FLUID,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -388,136 +39,40 @@ public class Application extends BaseDomain implements Artifact {
|
||||||
* EmbedSetting is used for embedding Appsmith apps on other platforms
|
* EmbedSetting is used for embedding Appsmith apps on other platforms
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public static class EmbedSetting {
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public static class EmbedSetting extends EmbedSettingCE {}
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String height;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String width;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private Boolean showNavigationBar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NavigationSetting stores the navigation configuration for the app
|
* NavigationSetting stores the navigation configuration for the app
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public static class NavigationSetting {
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@JsonView({Views.Public.class, Git.class})
|
public static class NavigationSetting extends NavigationSettingCE {}
|
||||||
private Boolean showNavbar;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String orientation;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String navStyle;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String position;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String itemStyle;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String colorStyle;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String logoAssetId;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String logoConfiguration;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private Boolean showSignIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AppPositioning captures widget positioning Mode of the application
|
* AppPositioning captures widget positioning Mode of the application
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
public static class AppPositioning extends AppPositioningCE {
|
||||||
public static class AppPositioning {
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
Type type;
|
|
||||||
|
|
||||||
public AppPositioning(String type) {
|
public AppPositioning(String type) {
|
||||||
setType(Type.valueOf(type));
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Type {
|
public AppPositioning(AppPositioning.Type type) {
|
||||||
FIXED,
|
super(type);
|
||||||
AUTO,
|
|
||||||
ANVIL
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public static class ThemeSetting {
|
public static class ThemeSetting extends ThemeSettingCE {
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String accentColor;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String borderRadius;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private float sizing = 1;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private float density = 1;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
private String fontFamily;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
Type colorMode;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
IconStyle iconStyle;
|
|
||||||
|
|
||||||
@JsonView({Views.Public.class, Git.class})
|
|
||||||
AppMaxWidth appMaxWidth = AppMaxWidth.LARGE;
|
|
||||||
|
|
||||||
public ThemeSetting(Type colorMode) {
|
public ThemeSetting(Type colorMode) {
|
||||||
this.colorMode = colorMode;
|
super(colorMode);
|
||||||
}
|
|
||||||
|
|
||||||
public enum Type {
|
|
||||||
LIGHT,
|
|
||||||
DARK
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum IconStyle {
|
|
||||||
OUTLINED,
|
|
||||||
FILLED
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum AppMaxWidth {
|
|
||||||
UNLIMITED,
|
|
||||||
LARGE,
|
|
||||||
MEDIUM,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Fields extends BaseDomain.Fields {
|
public static class Fields extends ApplicationCE.Fields {}
|
||||||
public static final String gitApplicationMetadata_gitAuth =
|
|
||||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.gitAuth);
|
|
||||||
public static final String gitApplicationMetadata_defaultApplicationId =
|
|
||||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.defaultApplicationId);
|
|
||||||
|
|
||||||
public static final String gitApplicationMetadata_defaultArtifactId =
|
|
||||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.defaultArtifactId);
|
|
||||||
public static final String gitApplicationMetadata_isAutoDeploymentEnabled =
|
|
||||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.isAutoDeploymentEnabled);
|
|
||||||
public static final String gitApplicationMetadata_branchName =
|
|
||||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.branchName);
|
|
||||||
public static final String gitApplicationMetadata_isRepoPrivate =
|
|
||||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.isRepoPrivate);
|
|
||||||
public static final String gitApplicationMetadata_isProtectedBranch =
|
|
||||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.isProtectedBranch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,124 +1,15 @@
|
||||||
package com.appsmith.server.domains;
|
package com.appsmith.server.domains;
|
||||||
|
|
||||||
import com.appsmith.external.models.AppsmithDomain;
|
import com.appsmith.external.models.AppsmithDomain;
|
||||||
import com.appsmith.external.views.Views;
|
import com.appsmith.server.domains.ce.GitArtifactMetadataCE;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonView;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.FieldNameConstants;
|
import lombok.experimental.FieldNameConstants;
|
||||||
import org.springframework.data.annotation.Transient;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
// This class will be used for one-to-one mapping for the DB application and the application present in the git repo.
|
// This class will be used for one-to-one mapping for the DB application and the application present in the git repo.
|
||||||
@Data
|
@Data
|
||||||
@FieldNameConstants
|
@FieldNameConstants
|
||||||
public class GitArtifactMetadata implements AppsmithDomain {
|
@EqualsAndHashCode(callSuper = true)
|
||||||
// Git branch corresponding to this application, we have one to one mapping for application in DB with git-branch
|
public class GitArtifactMetadata extends GitArtifactMetadataCE implements AppsmithDomain {
|
||||||
@JsonView(Views.Public.class)
|
public static class Fields extends GitArtifactMetadataCE.Fields {}
|
||||||
String branchName;
|
|
||||||
|
|
||||||
// Git default branch corresponding to the remote git repo to which the application is connected to
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String defaultBranchName;
|
|
||||||
|
|
||||||
// Git remote url will be used while pushing and pulling changes
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String remoteUrl;
|
|
||||||
|
|
||||||
// Git remote https url will be used while checking if the repo is public or private
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String browserSupportedRemoteUrl;
|
|
||||||
|
|
||||||
// If remote repo is private and will be stored only with default application
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Boolean isRepoPrivate;
|
|
||||||
|
|
||||||
// The name of git repo
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String repoName;
|
|
||||||
|
|
||||||
// Default application id used for storing the application files in local volume :
|
|
||||||
// container-volumes/git_repo/workspaceId/defaultApplicationId/branchName/applicationDirectoryStructure...
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String defaultApplicationId;
|
|
||||||
|
|
||||||
// We are maintaining this attribute separately from defaultApplicationId to maintain backward compatibility with
|
|
||||||
// the directory structure that folks might on their file systems
|
|
||||||
// Default artifact id used for storing the artifact files in local volume :
|
|
||||||
// container-volumes/git_repo/workspaceId/artifactType/defaultArtifactId/branchName/artifactDirectoryStructure...
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String defaultArtifactId;
|
|
||||||
|
|
||||||
// Git credentials used to push changes to remote repo and will be stored with default application only to optimise
|
|
||||||
// space requirement and update operation
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
GitAuth gitAuth;
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Map<String, GitProfile> gitProfiles;
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String publicKey;
|
|
||||||
|
|
||||||
// Deploy key documentation url
|
|
||||||
@Transient
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
String docUrl;
|
|
||||||
|
|
||||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssX", timezone = "UTC")
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
Instant lastCommittedAt;
|
|
||||||
|
|
||||||
@JsonView(Views.Metadata.class)
|
|
||||||
List<String> branchProtectionRules;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This field is no more used and will be removed in future version.
|
|
||||||
* Please use the branchProtectionRules field to know whether a branch is protected or not.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@JsonView(Views.Internal.class)
|
|
||||||
Boolean isProtectedBranch;
|
|
||||||
|
|
||||||
@JsonView(Views.Metadata.class)
|
|
||||||
AutoCommitConfig autoCommitConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Boolean flag to store whether auto deployment is enabled for any branch of this application.
|
|
||||||
* If true, any branch of this application can be automatically deployed using git web hook.
|
|
||||||
*/
|
|
||||||
@JsonView(Views.Metadata.class)
|
|
||||||
boolean isAutoDeploymentEnabled;
|
|
||||||
|
|
||||||
public AutoCommitConfig getAutoCommitConfig() {
|
|
||||||
// by default, the auto commit should be enabled.
|
|
||||||
// new AutoCommitConfig will have enabled=true so we're returning a new object when field is null
|
|
||||||
if (autoCommitConfig == null) {
|
|
||||||
autoCommitConfig = new AutoCommitConfig();
|
|
||||||
}
|
|
||||||
return autoCommitConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
|
||||||
public String getDefaultArtifactId() {
|
|
||||||
if (StringUtils.hasText(defaultArtifactId)) {
|
|
||||||
return defaultArtifactId;
|
|
||||||
} else return defaultApplicationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : Set to private to prevent direct access unless migration is performed
|
|
||||||
private void setDefaultArtifactId(String defaultArtifactId) {
|
|
||||||
this.defaultArtifactId = defaultArtifactId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultApplicationId(String defaultApplicationId) {
|
|
||||||
this.defaultApplicationId = defaultApplicationId;
|
|
||||||
this.defaultArtifactId = defaultApplicationId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,525 @@
|
||||||
|
package com.appsmith.server.domains.ce;
|
||||||
|
|
||||||
|
import com.appsmith.external.models.BaseDomain;
|
||||||
|
import com.appsmith.external.views.Git;
|
||||||
|
import com.appsmith.external.views.Views;
|
||||||
|
import com.appsmith.server.constants.ArtifactType;
|
||||||
|
import com.appsmith.server.domains.Application;
|
||||||
|
import com.appsmith.server.domains.ApplicationDetail;
|
||||||
|
import com.appsmith.server.domains.ApplicationPage;
|
||||||
|
import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
|
import com.appsmith.server.dtos.CustomJSLibContextDTO;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldNameConstants;
|
||||||
|
import org.springframework.data.annotation.Transient;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static com.appsmith.external.helpers.StringUtils.dotted;
|
||||||
|
import static com.appsmith.server.constants.ResourceModes.EDIT;
|
||||||
|
import static com.appsmith.server.constants.ResourceModes.VIEW;
|
||||||
|
import static com.appsmith.server.helpers.DateUtils.ISO_FORMATTER;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Document
|
||||||
|
@FieldNameConstants
|
||||||
|
public class ApplicationCE extends BaseDomain implements ArtifactCE {
|
||||||
|
|
||||||
|
@NotNull @JsonView(Views.Public.class)
|
||||||
|
String name;
|
||||||
|
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String workspaceId;
|
||||||
|
|
||||||
|
// TODO: remove default values from application
|
||||||
|
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Boolean isPublic = false;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
List<ApplicationPage> pages;
|
||||||
|
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
List<ApplicationPage> publishedPages;
|
||||||
|
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
@Transient
|
||||||
|
Boolean viewMode = false;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
boolean appIsExample = false;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
long unreadCommentThreads;
|
||||||
|
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
String clonedFromApplicationId;
|
||||||
|
|
||||||
|
@JsonView({Views.Internal.class, Git.class})
|
||||||
|
ApplicationDetail unpublishedApplicationDetail;
|
||||||
|
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
ApplicationDetail publishedApplicationDetail;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
String color;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
String icon;
|
||||||
|
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
private String slug;
|
||||||
|
|
||||||
|
@JsonView({Views.Internal.class, Git.class})
|
||||||
|
Application.AppLayout unpublishedAppLayout;
|
||||||
|
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
Application.AppLayout publishedAppLayout;
|
||||||
|
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Set<CustomJSLibContextDTO> unpublishedCustomJSLibs;
|
||||||
|
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Set<CustomJSLibContextDTO> publishedCustomJSLibs;
|
||||||
|
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
GitArtifactMetadata gitApplicationMetadata;
|
||||||
|
|
||||||
|
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Instant lastDeployedAt; // when this application was last deployed
|
||||||
|
|
||||||
|
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
Integer evaluationVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* applicationVersion will be used when we've a breaking change in application, and it's not possible to write a
|
||||||
|
* migration. User need to update the application manually.
|
||||||
|
* In such cases, we can use this field to determine whether we need to notify user about that breaking change
|
||||||
|
* so that they can update their application.
|
||||||
|
* Once updated, we should set applicationVersion to latest version as well.
|
||||||
|
*/
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
Integer applicationVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changing name, change in pages, widgets and datasources will set lastEditedAt.
|
||||||
|
* Other activities e.g. changing policy will not change this property.
|
||||||
|
* We're adding JsonIgnore here because it'll be exposed as modifiedAt to keep it backward compatible
|
||||||
|
*/
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
Instant lastEditedAt;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
Application.EmbedSetting embedSetting;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
Boolean collapseInvisibleWidgets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Earlier this was returning value of the updatedAt property in the base domain.
|
||||||
|
* As this property is modified by the framework when there is any change in domain,
|
||||||
|
* a new property lastEditedAt has been added to track the edit actions from users.
|
||||||
|
* This method exposes that property.
|
||||||
|
*
|
||||||
|
* @return updated time as a string
|
||||||
|
*/
|
||||||
|
@JsonProperty(value = "modifiedAt", access = JsonProperty.Access.READ_ONLY)
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
public String getLastUpdateTime() {
|
||||||
|
if (lastEditedAt != null) {
|
||||||
|
return ISO_FORMATTER.format(lastEditedAt);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
public String getLastDeployedAt() {
|
||||||
|
if (lastDeployedAt != null) {
|
||||||
|
return ISO_FORMATTER.format(lastDeployedAt);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Boolean forkingEnabled;
|
||||||
|
|
||||||
|
// Field to convey if the application is updated by the user
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Boolean isManualUpdate;
|
||||||
|
|
||||||
|
// Field to convey if the application is modified from the DB migration
|
||||||
|
@Transient
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Boolean isAutoUpdate;
|
||||||
|
|
||||||
|
// To convey current schema version for client and server. This will be used to check if we run the migration
|
||||||
|
// between 2 commits if the application is connected to git
|
||||||
|
@JsonView({Views.Internal.class, Git.class})
|
||||||
|
Integer clientSchemaVersion;
|
||||||
|
|
||||||
|
@JsonView({Views.Internal.class, Git.class})
|
||||||
|
Integer serverSchemaVersion;
|
||||||
|
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
String publishedModeThemeId;
|
||||||
|
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
String editModeThemeId;
|
||||||
|
|
||||||
|
// TODO Temporary provision for exporting the application with datasource configuration for the sample/template apps
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Boolean exportWithConfiguration;
|
||||||
|
|
||||||
|
// forkWithConfiguration represents whether credentials are shared or not while forking an app
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Boolean forkWithConfiguration;
|
||||||
|
|
||||||
|
// isCommunityTemplate represents whether this application has been published as a community template
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Boolean isCommunityTemplate;
|
||||||
|
|
||||||
|
/* Template title of the template from which this app was forked, if any */
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String forkedFromTemplateTitle;
|
||||||
|
|
||||||
|
// This constructor is used during clone application. It only deeply copies selected fields. The rest are either
|
||||||
|
// initialized newly or is left up to the calling function to set.
|
||||||
|
public ApplicationCE(ApplicationCE application) {
|
||||||
|
super();
|
||||||
|
this.workspaceId = application.getWorkspaceId();
|
||||||
|
this.pages = new ArrayList<>();
|
||||||
|
this.publishedPages = new ArrayList<>();
|
||||||
|
this.clonedFromApplicationId = application.getId();
|
||||||
|
this.color = application.getColor();
|
||||||
|
this.icon = application.getIcon();
|
||||||
|
this.unpublishedAppLayout = application.getUnpublishedAppLayout() == null
|
||||||
|
? null
|
||||||
|
: new Application.AppLayout(application.getUnpublishedAppLayout().type);
|
||||||
|
this.publishedAppLayout = application.getPublishedAppLayout() == null
|
||||||
|
? null
|
||||||
|
: new Application.AppLayout(application.getPublishedAppLayout().type);
|
||||||
|
this.setUnpublishedApplicationDetail(new ApplicationDetail());
|
||||||
|
this.setPublishedApplicationDetail(new ApplicationDetail());
|
||||||
|
if (application.getUnpublishedApplicationDetail() == null) {
|
||||||
|
application.setUnpublishedApplicationDetail(new ApplicationDetail());
|
||||||
|
}
|
||||||
|
if (application.getPublishedApplicationDetail() == null) {
|
||||||
|
application.setPublishedApplicationDetail(new ApplicationDetail());
|
||||||
|
}
|
||||||
|
|
||||||
|
Application.AppPositioning unpublishedAppPositioning =
|
||||||
|
application.getUnpublishedApplicationDetail().getAppPositioning() == null
|
||||||
|
? null
|
||||||
|
: new Application.AppPositioning(
|
||||||
|
application.getUnpublishedApplicationDetail().getAppPositioning().type);
|
||||||
|
this.getUnpublishedApplicationDetail().setAppPositioning(unpublishedAppPositioning);
|
||||||
|
Application.AppPositioning publishedAppPositioning =
|
||||||
|
application.getPublishedApplicationDetail().getAppPositioning() == null
|
||||||
|
? null
|
||||||
|
: new Application.AppPositioning(
|
||||||
|
application.getPublishedApplicationDetail().getAppPositioning().type);
|
||||||
|
this.getPublishedApplicationDetail().setAppPositioning(publishedAppPositioning);
|
||||||
|
this.getUnpublishedApplicationDetail()
|
||||||
|
.setNavigationSetting(
|
||||||
|
application.getUnpublishedApplicationDetail().getNavigationSetting() == null
|
||||||
|
? null
|
||||||
|
: new Application.NavigationSetting());
|
||||||
|
this.getPublishedApplicationDetail()
|
||||||
|
.setNavigationSetting(
|
||||||
|
application.getPublishedApplicationDetail().getNavigationSetting() == null
|
||||||
|
? null
|
||||||
|
: new Application.NavigationSetting());
|
||||||
|
this.getUnpublishedApplicationDetail()
|
||||||
|
.setThemeSetting(
|
||||||
|
application.getUnpublishedApplicationDetail().getThemeSetting() == null
|
||||||
|
? null
|
||||||
|
: new Application.ThemeSetting());
|
||||||
|
this.getPublishedApplicationDetail()
|
||||||
|
.setThemeSetting(
|
||||||
|
application.getPublishedApplicationDetail().getThemeSetting() == null
|
||||||
|
? null
|
||||||
|
: new Application.ThemeSetting());
|
||||||
|
this.unpublishedCustomJSLibs = application.getUnpublishedCustomJSLibs();
|
||||||
|
this.collapseInvisibleWidgets = application.getCollapseInvisibleWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exportApplicationPages(final Map<String, String> pageIdToNameMap) {
|
||||||
|
for (ApplicationPage applicationPage : this.getPages()) {
|
||||||
|
applicationPage.setId(pageIdToNameMap.get(applicationPage.getId() + EDIT));
|
||||||
|
applicationPage.setDefaultPageId(null);
|
||||||
|
}
|
||||||
|
for (ApplicationPage applicationPage : this.getPublishedPages()) {
|
||||||
|
applicationPage.setId(pageIdToNameMap.get(applicationPage.getId() + VIEW));
|
||||||
|
applicationPage.setDefaultPageId(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBaseId() {
|
||||||
|
if (this.getGitArtifactMetadata() != null
|
||||||
|
&& StringUtils.hasLength(this.getGitArtifactMetadata().getDefaultArtifactId())) {
|
||||||
|
return this.getGitArtifactMetadata().getDefaultArtifactId();
|
||||||
|
}
|
||||||
|
return ArtifactCE.super.getBaseId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
@Override
|
||||||
|
public GitArtifactMetadata getGitArtifactMetadata() {
|
||||||
|
return this.gitApplicationMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
@Override
|
||||||
|
public void setGitArtifactMetadata(GitArtifactMetadata gitArtifactMetadata) {
|
||||||
|
this.gitApplicationMetadata = gitArtifactMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUnpublishedThemeId() {
|
||||||
|
return this.getEditModeThemeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUnpublishedThemeId(String themeId) {
|
||||||
|
this.setEditModeThemeId(themeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPublishedThemeId() {
|
||||||
|
return this.getPublishedModeThemeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPublishedThemeId(String themeId) {
|
||||||
|
this.setPublishedModeThemeId(themeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sanitiseToExportDBObject() {
|
||||||
|
this.setWorkspaceId(null);
|
||||||
|
this.setModifiedBy(null);
|
||||||
|
this.setCreatedBy(null);
|
||||||
|
this.setLastDeployedAt(null);
|
||||||
|
this.setLastEditedAt(null);
|
||||||
|
this.setGitApplicationMetadata(null);
|
||||||
|
this.setEditModeThemeId(null);
|
||||||
|
this.setPublishedModeThemeId(null);
|
||||||
|
this.setClientSchemaVersion(null);
|
||||||
|
this.setServerSchemaVersion(null);
|
||||||
|
this.setIsManualUpdate(false);
|
||||||
|
this.setPublishedCustomJSLibs(new HashSet<>());
|
||||||
|
this.setExportWithConfiguration(null);
|
||||||
|
this.setForkWithConfiguration(null);
|
||||||
|
this.setForkingEnabled(null);
|
||||||
|
super.sanitiseToExportDBObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ApplicationPage> getPages() {
|
||||||
|
return Boolean.TRUE.equals(viewMode) ? publishedPages : pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Application.AppLayout getAppLayout() {
|
||||||
|
return Boolean.TRUE.equals(viewMode) ? publishedAppLayout : unpublishedAppLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAppLayout(Application.AppLayout appLayout) {
|
||||||
|
if (Boolean.TRUE.equals(viewMode)) {
|
||||||
|
publishedAppLayout = appLayout;
|
||||||
|
} else {
|
||||||
|
unpublishedAppLayout = appLayout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationDetail getApplicationDetail() {
|
||||||
|
return Boolean.TRUE.equals(viewMode) ? publishedApplicationDetail : unpublishedApplicationDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApplicationDetail(ApplicationDetail applicationDetail) {
|
||||||
|
if (Boolean.TRUE.equals(viewMode)) {
|
||||||
|
publishedApplicationDetail = applicationDetail;
|
||||||
|
} else {
|
||||||
|
unpublishedApplicationDetail = applicationDetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@JsonView({Views.Internal.class})
|
||||||
|
public ArtifactType getArtifactType() {
|
||||||
|
return ArtifactType.APPLICATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class AppLayoutCE implements Serializable {
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
protected Type type;
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
DESKTOP,
|
||||||
|
TABLET_LARGE,
|
||||||
|
TABLET,
|
||||||
|
MOBILE,
|
||||||
|
FLUID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EmbedSetting is used for embedding Appsmith apps on other platforms
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class EmbedSettingCE {
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String height;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String width;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private Boolean showNavigationBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NavigationSetting stores the navigation configuration for the app
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class NavigationSettingCE {
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private Boolean showNavbar;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String orientation;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String navStyle;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String position;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String itemStyle;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String colorStyle;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String logoAssetId;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String logoConfiguration;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private Boolean showSignIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AppPositioning captures widget positioning Mode of the application
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class AppPositioningCE {
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
protected Type type;
|
||||||
|
|
||||||
|
public AppPositioningCE(String type) {
|
||||||
|
setType(Type.valueOf(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
FIXED,
|
||||||
|
AUTO,
|
||||||
|
ANVIL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class ThemeSettingCE {
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String accentColor;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String borderRadius;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private float sizing = 1;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private float density = 1;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
private String fontFamily;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
protected Type colorMode;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
IconStyle iconStyle;
|
||||||
|
|
||||||
|
@JsonView({Views.Public.class, Git.class})
|
||||||
|
AppMaxWidth appMaxWidth = AppMaxWidth.LARGE;
|
||||||
|
|
||||||
|
public ThemeSettingCE(Type colorMode) {
|
||||||
|
this.colorMode = colorMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
LIGHT,
|
||||||
|
DARK
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum IconStyle {
|
||||||
|
OUTLINED,
|
||||||
|
FILLED
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AppMaxWidth {
|
||||||
|
UNLIMITED,
|
||||||
|
LARGE,
|
||||||
|
MEDIUM,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Fields extends BaseDomain.Fields {
|
||||||
|
public static final String gitApplicationMetadata_gitAuth =
|
||||||
|
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.gitAuth);
|
||||||
|
public static final String gitApplicationMetadata_defaultApplicationId =
|
||||||
|
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.defaultApplicationId);
|
||||||
|
public static final String gitApplicationMetadata_defaultArtifactId =
|
||||||
|
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.defaultArtifactId);
|
||||||
|
public static final String gitApplicationMetadata_branchName =
|
||||||
|
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.branchName);
|
||||||
|
public static final String gitApplicationMetadata_isRepoPrivate =
|
||||||
|
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.isRepoPrivate);
|
||||||
|
public static final String gitApplicationMetadata_isProtectedBranch =
|
||||||
|
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.isProtectedBranch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
package com.appsmith.server.domains.ce;
|
||||||
|
|
||||||
|
import com.appsmith.external.models.AppsmithDomain;
|
||||||
|
import com.appsmith.external.views.Views;
|
||||||
|
import com.appsmith.server.domains.AutoCommitConfig;
|
||||||
|
import com.appsmith.server.domains.GitAuth;
|
||||||
|
import com.appsmith.server.domains.GitProfile;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.FieldNameConstants;
|
||||||
|
import org.springframework.data.annotation.Transient;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
// This class will be used for one-to-one mapping for the DB application and the application present in the git repo.
|
||||||
|
@Data
|
||||||
|
@FieldNameConstants
|
||||||
|
public class GitArtifactMetadataCE implements AppsmithDomain {
|
||||||
|
// Git branch corresponding to this application, we have one to one mapping for application in DB with git-branch
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String branchName;
|
||||||
|
|
||||||
|
// Git default branch corresponding to the remote git repo to which the application is connected to
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String defaultBranchName;
|
||||||
|
|
||||||
|
// Git remote url will be used while pushing and pulling changes
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String remoteUrl;
|
||||||
|
|
||||||
|
// Git remote https url will be used while checking if the repo is public or private
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String browserSupportedRemoteUrl;
|
||||||
|
|
||||||
|
// If remote repo is private and will be stored only with default application
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Boolean isRepoPrivate;
|
||||||
|
|
||||||
|
// The name of git repo
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String repoName;
|
||||||
|
|
||||||
|
// Default application id used for storing the application files in local volume :
|
||||||
|
// container-volumes/git_repo/workspaceId/defaultApplicationId/branchName/applicationDirectoryStructure...
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String defaultApplicationId;
|
||||||
|
|
||||||
|
// We are maintaining this attribute separately from defaultApplicationId to maintain backward compatibility with
|
||||||
|
// the directory structure that folks might on their file systems
|
||||||
|
// Default artifact id used for storing the artifact files in local volume :
|
||||||
|
// container-volumes/git_repo/workspaceId/artifactType/defaultArtifactId/branchName/artifactDirectoryStructure...
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String defaultArtifactId;
|
||||||
|
|
||||||
|
// Git credentials used to push changes to remote repo and will be stored with default application only to optimise
|
||||||
|
// space requirement and update operation
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
GitAuth gitAuth;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Map<String, GitProfile> gitProfiles;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String publicKey;
|
||||||
|
|
||||||
|
// Deploy key documentation url
|
||||||
|
@Transient
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
String docUrl;
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssX", timezone = "UTC")
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
Instant lastCommittedAt;
|
||||||
|
|
||||||
|
@JsonView(Views.Metadata.class)
|
||||||
|
List<String> branchProtectionRules;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This field is no more used and will be removed in future version.
|
||||||
|
* Please use the branchProtectionRules field to know whether a branch is protected or not.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@JsonView(Views.Internal.class)
|
||||||
|
Boolean isProtectedBranch;
|
||||||
|
|
||||||
|
@JsonView(Views.Metadata.class)
|
||||||
|
AutoCommitConfig autoCommitConfig;
|
||||||
|
|
||||||
|
public AutoCommitConfig getAutoCommitConfig() {
|
||||||
|
// by default, the auto commit should be enabled.
|
||||||
|
// new AutoCommitConfig will have enabled=true so we're returning a new object when field is null
|
||||||
|
if (autoCommitConfig == null) {
|
||||||
|
autoCommitConfig = new AutoCommitConfig();
|
||||||
|
}
|
||||||
|
return autoCommitConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonView(Views.Public.class)
|
||||||
|
public String getDefaultArtifactId() {
|
||||||
|
if (StringUtils.hasText(defaultArtifactId)) {
|
||||||
|
return defaultArtifactId;
|
||||||
|
} else return defaultApplicationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : Set to private to prevent direct access unless migration is performed
|
||||||
|
private void setDefaultArtifactId(String defaultArtifactId) {
|
||||||
|
this.defaultArtifactId = defaultArtifactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultApplicationId(String defaultApplicationId) {
|
||||||
|
this.defaultApplicationId = defaultApplicationId;
|
||||||
|
this.defaultArtifactId = defaultApplicationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Fields {}
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,11 @@ public class EqualityTest {
|
||||||
|
|
||||||
private final Set<Class<?>> TESTED_CLASSES = Set.of(
|
private final Set<Class<?>> TESTED_CLASSES = Set.of(
|
||||||
// Note: Adding a class here means that we have a test for its equality in this file.
|
// Note: Adding a class here means that we have a test for its equality in this file.
|
||||||
ApplicationDetail.class, TenantConfiguration.class);
|
ApplicationDetail.class,
|
||||||
|
TenantConfiguration.class,
|
||||||
|
Application.AppLayout.class,
|
||||||
|
Application.EmbedSetting.class,
|
||||||
|
GitArtifactMetadata.class);
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -72,4 +76,55 @@ public class EqualityTest {
|
||||||
assertThat(d1).isEqualTo(d2);
|
assertThat(d1).isEqualTo(d2);
|
||||||
assertThat(d1).isNotEqualTo(d3);
|
assertThat(d1).isNotEqualTo(d3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAppLayout() {
|
||||||
|
Application.AppLayout a1 = new Application.AppLayout(Application.AppLayout.Type.DESKTOP);
|
||||||
|
Application.AppLayout a2 = new Application.AppLayout(Application.AppLayout.Type.DESKTOP);
|
||||||
|
Application.AppLayout a3 = new Application.AppLayout(Application.AppLayout.Type.MOBILE);
|
||||||
|
assertThat(a1).isEqualTo(a2).isNotEqualTo(a3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAppEmbedSetting() {
|
||||||
|
Application.EmbedSetting a1 = new Application.EmbedSetting();
|
||||||
|
a1.setHeight("5");
|
||||||
|
a1.setWidth("5");
|
||||||
|
a1.setShowNavigationBar(Boolean.TRUE);
|
||||||
|
Application.EmbedSetting a2 = new Application.EmbedSetting();
|
||||||
|
a2.setHeight("5");
|
||||||
|
a2.setWidth("5");
|
||||||
|
a2.setShowNavigationBar(Boolean.TRUE);
|
||||||
|
Application.EmbedSetting a3 = new Application.EmbedSetting();
|
||||||
|
a3.setHeight("5");
|
||||||
|
a3.setWidth("5");
|
||||||
|
a3.setShowNavigationBar(Boolean.FALSE);
|
||||||
|
assertThat(a1).isEqualTo(a2).isNotEqualTo(a3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testArtifactEquality() {
|
||||||
|
String remoteUrl1 = "protocol://domain.superdomain";
|
||||||
|
String remoteUrl2 = "protocol://domain.superdomain2";
|
||||||
|
|
||||||
|
GitArtifactMetadata a1 = new GitArtifactMetadata();
|
||||||
|
a1.setRemoteUrl(remoteUrl1);
|
||||||
|
GitArtifactMetadata a2 = new GitArtifactMetadata();
|
||||||
|
a2.setRemoteUrl(remoteUrl1);
|
||||||
|
GitArtifactMetadata a3 = new GitArtifactMetadata();
|
||||||
|
a3.setRemoteUrl(remoteUrl2);
|
||||||
|
|
||||||
|
assertThat(a1).isEqualTo(a2).isNotEqualTo(a3);
|
||||||
|
|
||||||
|
a1.setAutoCommitConfig(new AutoCommitConfig());
|
||||||
|
a2.setAutoCommitConfig(new AutoCommitConfig());
|
||||||
|
a3.setAutoCommitConfig(new AutoCommitConfig());
|
||||||
|
|
||||||
|
assertThat(a1).isEqualTo(a2).isNotEqualTo(a3);
|
||||||
|
|
||||||
|
a1.getAutoCommitConfig().setEnabled(Boolean.TRUE);
|
||||||
|
a2.getAutoCommitConfig().setEnabled(Boolean.FALSE);
|
||||||
|
|
||||||
|
assertThat(a1).isNotEqualTo(a2).isNotEqualTo(a3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user