Add more devices in AppLayout options (#3451)

* Remove width and introduce more AppLayout type enums

* Fix: Adding min width to layout options.

Co-authored-by: Ashok Kumar M <35134347+marks0351@users.noreply.github.com>
This commit is contained in:
Shrikant Sharat Kandula 2021-03-11 07:51:48 +05:30 committed by GitHub
parent f5ec68edfe
commit 65568a4e13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 155 additions and 45 deletions

View File

@ -17,7 +17,7 @@ describe("Dynamic Layout Functionality", function() {
.click({ force: true });
cy.get(commonlocators.canvas)
.invoke("width")
.should("be.eq", 720);
.should("be.eq", 450);
});
it("Dynamic Layout - New Page should have selected Layout", function() {
cy.get(pages.AddPage)
@ -25,6 +25,6 @@ describe("Dynamic Layout Functionality", function() {
.click();
cy.get(commonlocators.canvas)
.invoke("width")
.should("be.eq", 720);
.should("be.eq", 450);
});
});

View File

@ -1,8 +1,5 @@
import localStorage from "utils/localStorage";
export const CANVAS_DEFAULT_WIDTH_PX = 1224;
export const CANVAS_TABLET_WIDTH_PX = 1024;
export const CANVAS_MOBILE_WIDTH_PX = 720;
export const CANVAS_DEFAULT_HEIGHT_PX = 1292;
export const CANVAS_DEFAULT_GRID_HEIGHT_PX = 1;
export const CANVAS_DEFAULT_GRID_WIDTH_PX = 1;

View File

@ -1,3 +1,5 @@
import { SupportedLayouts } from "reducers/entityReducers/pageListReducer";
export enum WidgetTypes {
BUTTON_WIDGET = "BUTTON_WIDGET",
TEXT_WIDGET = "TEXT_WIDGET",
@ -71,6 +73,27 @@ export const CSSUnits: { [id: string]: CSSUnit } = {
RELATIVE_PARENT: "%",
};
interface LayoutConfig {
minWidth: number;
maxWidth: number;
}
type LayoutConfigurations = Record<SupportedLayouts, LayoutConfig>;
export const DefaultLayoutType: SupportedLayouts = "DESKTOP";
export const layoutConfigurations: LayoutConfigurations = {
TABLET_LARGE: {
minWidth: 960,
maxWidth: 1080,
},
MOBILE: {
minWidth: 350,
maxWidth: 450,
},
DESKTOP: { minWidth: 1160, maxWidth: 1280 },
TABLET: { minWidth: 650, maxWidth: 800 },
FLUID: { minWidth: -1, maxWidth: -1 },
};
export const GridDefaults = {
DEFAULT_CELL_SIZE: 1,
DEFAULT_WIDGET_WIDTH: 200,

View File

@ -1,18 +1,13 @@
import { updateApplicationLayout } from "actions/applicationActions";
import Dropdown from "components/ads/Dropdown";
import Icon, { IconName, IconSize } from "components/ads/Icon";
import {
CANVAS_DEFAULT_WIDTH_PX,
CANVAS_MOBILE_WIDTH_PX,
CANVAS_TABLET_WIDTH_PX,
} from "constants/AppConstants";
import { Colors } from "constants/Colors";
import React from "react";
import { useDispatch } from "react-redux";
import { AppState } from "reducers";
import {
AppLayoutConfig,
AppLayoutType,
SupportedLayouts,
} from "reducers/entityReducers/pageListReducer";
import {
getCurrentApplicationId,
@ -23,17 +18,14 @@ import { useSelector } from "store";
import styled, { ThemeProvider } from "styled-components";
import { noop } from "utils/AppsmithUtils";
type SupportedLayouts = "Desktop" | "Tablet" | "Mobile Device" | "Fluid Width";
interface AppsmithLayoutConfigOption {
name: SupportedLayouts;
type: AppLayoutType;
width: number;
name: string;
type: SupportedLayouts;
icon?: IconName;
}
export const AppsmithDefaultLayout: AppLayoutConfig = {
type: "FLUID",
width: CANVAS_DEFAULT_WIDTH_PX,
type: "DESKTOP",
};
const AppsmithLayouts: AppsmithLayoutConfigOption[] = [
@ -42,22 +34,24 @@ const AppsmithLayouts: AppsmithLayoutConfigOption[] = [
...AppsmithDefaultLayout,
icon: "desktop",
},
{
name: "Tablet(Large)",
type: "TABLET_LARGE",
icon: "tablet",
},
{
name: "Tablet",
type: "FLUID",
width: CANVAS_TABLET_WIDTH_PX,
type: "TABLET",
icon: "tablet",
},
{
name: "Mobile Device",
type: "FLUID",
width: CANVAS_MOBILE_WIDTH_PX,
type: "MOBILE",
icon: "mobile",
},
{
name: "Fluid Width",
type: "FLUID",
width: -1,
icon: "fluid",
},
];
@ -100,15 +94,11 @@ export const MainContainerLayoutControl: React.FC<any> = () => {
onSelect: () =>
updateAppLayout({
type: each.type,
width: each.width,
}),
};
});
const selectedLayout = appLayout
? layoutOptions.find(
(each) =>
each.type === appLayout.type && each.width === appLayout.width,
)
? layoutOptions.find((each) => each.type === appLayout.type)
: layoutOptions[0];
const dispatch = useDispatch();
const lightTheme = useSelector((state: AppState) =>
@ -116,12 +106,11 @@ export const MainContainerLayoutControl: React.FC<any> = () => {
);
const updateAppLayout = (layoutConfig: AppLayoutConfig) => {
const { type, width } = layoutConfig;
const { type } = layoutConfig;
dispatch(
updateApplicationLayout(appId || "", {
appLayout: {
type,
width,
},
}),
);

View File

@ -105,10 +105,14 @@ export const pageListReducer = createReducer(initialState, {
},
});
export type AppLayoutType = "FIXED" | "FLUID";
export type SupportedLayouts =
| "DESKTOP"
| "TABLET_LARGE"
| "TABLET"
| "MOBILE"
| "FLUID";
export interface AppLayoutConfig {
type: AppLayoutType;
width: number;
type: SupportedLayouts;
}
export interface PageListReduxState {

View File

@ -1,5 +1,9 @@
import { theme } from "constants/DefaultTheme";
import { ReduxActionTypes } from "constants/ReduxActionConstants";
import {
DefaultLayoutType,
layoutConfigurations,
} from "constants/WidgetConstants";
import { debounce } from "lodash";
import { AppsmithDefaultLayout } from "pages/Editor/MainContainerLayoutControl";
import { useCallback, useEffect } from "react";
@ -41,13 +45,17 @@ export const useDynamicAppLayout = () => {
screenWidth: number,
appLayout = AppsmithDefaultLayout,
) => {
const { type, width: layoutMaxWidth } = appLayout;
const layoutWidth =
type === "FLUID"
? calculateFluidMaxWidth(screenWidth, layoutMaxWidth)
: layoutMaxWidth;
const { type } = appLayout;
const { minWidth = -1, maxWidth = -1 } =
layoutConfigurations[type] || layoutConfigurations[DefaultLayoutType];
const calculatedMinWidth =
appMode === "EDIT" ? minWidth - parseInt(theme.sidebarWidth) : minWidth;
const layoutWidth = calculateFluidMaxWidth(screenWidth, maxWidth);
const { rightColumn } = mainContainer;
if (rightColumn !== layoutWidth) {
if (
(type === "FLUID" || calculatedMinWidth <= layoutWidth) &&
rightColumn !== layoutWidth
) {
dispatch({
type: ReduxActionTypes.UPDATE_CANVAS_LAYOUT,
payload: {

View File

@ -71,10 +71,8 @@ public class Application extends BaseDomain {
this.clonedFromApplicationId = application.getId();
this.color = application.getColor();
this.icon = application.getIcon();
this.unpublishedAppLayout = application.getUnpublishedAppLayout() == null ? null
: new AppLayout(application.getUnpublishedAppLayout().type, application.getUnpublishedAppLayout().getWidth());
this.publishedAppLayout = application.getPublishedAppLayout() == null ? null
: new AppLayout(application.getPublishedAppLayout().type, application.getPublishedAppLayout().getWidth());
this.unpublishedAppLayout = application.getUnpublishedAppLayout() == null ? null : new AppLayout(application.getUnpublishedAppLayout().type);
this.publishedAppLayout = application.getPublishedAppLayout() == null ? null : new AppLayout(application.getPublishedAppLayout().type);
}
public List<ApplicationPage> getPages() {
@ -98,10 +96,24 @@ public class Application extends BaseDomain {
@AllArgsConstructor
public static class AppLayout implements Serializable {
Type type;
Integer width;
/**
* @deprecated The following field is deprecated and now removed, because it's needed in a migration. After the
* migration has been run, it may be removed (along with the migration or there'll be compile errors there).
*/
@JsonIgnore
@Deprecated(forRemoval = true)
Integer width = null;
public AppLayout(Type type) {
this.type = type;
}
public enum Type {
FIXED,
DESKTOP,
TABLET_LARGE,
TABLET,
MOBILE,
FLUID,
}
}

View File

@ -45,6 +45,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.cloudyrock.mongock.ChangeLog;
import com.github.cloudyrock.mongock.ChangeSet;
import com.google.gson.Gson;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
@ -60,11 +61,13 @@ import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.data.mongodb.core.CollectionCallback;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.index.CompoundIndexDefinition;
import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StreamUtils;
@ -1916,4 +1919,78 @@ public class DatabaseChangelog {
mongoTemplate.save(datasource);
});
}
@ChangeSet(order = "059", id = "change-applayout-type-definition", author = "")
public void changeAppLayoutTypeDefinition(MongoOperations mongoOperations, MongoClient mongoClient) {
// Unset an old version of this field, that is no longer used.
mongoOperations.updateMulti(
query(where("appLayout").exists(true)),
new Update().unset("appLayout"),
Application.class
);
// For the published and unpublished app layouts, migrate the old way of specifying the device width to the new
// way of doing it. Table of migrations:
// Desktop: Old - 1224, New 1160 - 1280
// Tablet L: Old - NA, New 960 - 1080
// Tablet: Old - 1024, New 650 - 800
// Mobile: Old - 720, New 350 - 450
final Criteria criteria = new Criteria().orOperator(
where(fieldName(QApplication.application.unpublishedAppLayout)).exists(true),
where(fieldName(QApplication.application.publishedAppLayout)).exists(true)
);
final Query query = query(criteria);
query.fields()
.include(fieldName(QApplication.application.unpublishedAppLayout))
.include(fieldName(QApplication.application.publishedAppLayout));
List<Application> apps = mongoOperations.find(query, Application.class);
for (final Application app : apps) {
final Integer unpublishedWidth = app.getUnpublishedAppLayout() == null ? null : app.getUnpublishedAppLayout().getWidth();
final Integer publishedWidth = app.getPublishedAppLayout() == null ? null : app.getPublishedAppLayout().getWidth();
final Update update = new Update().unset("unpublishedAppLayout.width").unset("publishedAppLayout.width");
if (unpublishedWidth != null) {
final String typeField = "unpublishedAppLayout.type";
if (unpublishedWidth == -1) {
update.set(typeField, Application.AppLayout.Type.FLUID.name());
} else {
if (unpublishedWidth == 1024) {
update.set(typeField, Application.AppLayout.Type.TABLET.name());
} else if (unpublishedWidth == 720) {
update.set(typeField, Application.AppLayout.Type.MOBILE.name());
} else {
// Default to Desktop.
update.set(typeField, Application.AppLayout.Type.DESKTOP.name());
}
}
}
if (publishedWidth != null) {
final String typeField = "publishedAppLayout.type";
if (publishedWidth == -1) {
update.set(typeField, Application.AppLayout.Type.FLUID.name());
} else {
if (publishedWidth == 1024) {
update.set(typeField, Application.AppLayout.Type.TABLET.name());
} else if (publishedWidth == 720) {
update.set(typeField, Application.AppLayout.Type.MOBILE.name());
} else {
// Default to Desktop.
update.set(typeField, Application.AppLayout.Type.DESKTOP.name());
}
}
}
mongoOperations.updateFirst(
query(where(fieldName(QApplication.application.id)).is(app.getId())),
update,
Application.class
);
}
}
}

View File

@ -697,7 +697,7 @@ public class ApplicationServiceTest {
Application testApplication = new Application();
String appName = "ApplicationServiceTest Publish Application";
testApplication.setName(appName);
testApplication.setAppLayout(new Application.AppLayout(Application.AppLayout.Type.FIXED, 1024));
testApplication.setAppLayout(new Application.AppLayout(Application.AppLayout.Type.DESKTOP));
Mono<Application> applicationMono = applicationPageService.createApplication(testApplication, orgId)
.flatMap(application -> applicationPageService.publish(application.getId()))
.then(applicationService.findByName(appName, MANAGE_APPLICATIONS))