diff --git a/src/components/Dashboard/Modals/SelectElement/Components/Overview/AvailableElementsOverview.tsx b/src/components/Dashboard/Modals/SelectElement/Components/Overview/AvailableElementsOverview.tsx
index be42293aa..0304bc473 100644
--- a/src/components/Dashboard/Modals/SelectElement/Components/Overview/AvailableElementsOverview.tsx
+++ b/src/components/Dashboard/Modals/SelectElement/Components/Overview/AvailableElementsOverview.tsx
@@ -111,38 +111,7 @@ export const AvailableElementTypes = ({
id: getLowestWrapper()?.id ?? 'default',
},
},
- shape: {
- sm: {
- location: {
- x: 0,
- y: 0,
- },
- size: {
- width: appTileDefinition.minWidth,
- height: appTileDefinition.minHeight,
- },
- },
- md: {
- location: {
- x: 0,
- y: 0,
- },
- size: {
- width: appTileDefinition.minWidth,
- height: appTileDefinition.minHeight,
- },
- },
- lg: {
- location: {
- x: 0,
- y: 0,
- },
- size: {
- width: appTileDefinition.minWidth,
- height: appTileDefinition.minHeight,
- },
- },
- },
+ shape: {},
integration: {
type: null,
properties: [],
diff --git a/src/components/Dashboard/Tiles/TileWrapper.tsx b/src/components/Dashboard/Tiles/TileWrapper.tsx
index f6469a2a4..47803e519 100644
--- a/src/components/Dashboard/Tiles/TileWrapper.tsx
+++ b/src/components/Dashboard/Tiles/TileWrapper.tsx
@@ -1,5 +1,6 @@
/* eslint-disable react/no-unknown-property */
import { ReactNode, RefObject } from 'react';
+import widgets from '../../../widgets';
interface GridstackTileWrapperProps {
id: string;
@@ -29,25 +30,46 @@ export const GridstackTileWrapper = ({
maxHeight,
children,
itemRef,
-}: GridstackTileWrapperProps) => (
-
- {children}
-
-);
+}: GridstackTileWrapperProps) => {
+ const locationProperties = useLocationProperties(x, y);
+ const normalizedWidth = width ?? minWidth;
+
+ const normalizedHeight = height ?? minHeight;
+
+ return (
+
+ {children}
+
+ );
+};
+
+const useLocationProperties = (x: number | undefined, y: number | undefined) => {
+ const isLocationDefined = x !== undefined && y !== undefined;
+
+ if (!isLocationDefined) {
+ return {
+ 'gs-auto-position': 'true',
+ };
+ }
+
+ return {
+ 'gs-x': x.toString(),
+ 'data-gridstack-x': x.toString(),
+ 'gs-y': y.toString(),
+ 'data-gridstack-y': y.toString(),
+ };
+};
diff --git a/src/components/Dashboard/Wrappers/WrapperContent.tsx b/src/components/Dashboard/Wrappers/WrapperContent.tsx
index cfb82ae39..5a864b6ab 100644
--- a/src/components/Dashboard/Wrappers/WrapperContent.tsx
+++ b/src/components/Dashboard/Wrappers/WrapperContent.tsx
@@ -34,8 +34,8 @@ export function WrapperContent({ apps, refs, widgets }: WrapperContentProps) {
key={app.id}
itemRef={refs.items.current[app.id]}
{...tile}
- {...app.shape[shapeSize]?.location}
- {...app.shape[shapeSize]?.size}
+ {...(app.shape[shapeSize]?.location ?? {})}
+ {...(app.shape[shapeSize]?.size ?? {})}
>
diff --git a/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts b/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts
index 36836222d..6da312a9d 100644
--- a/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts
+++ b/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts
@@ -1,4 +1,4 @@
-import { GridStack, GridStackNode } from 'fily-publish-gridstack';
+import { GridItemHTMLElement, GridStack, GridStackNode } from 'fily-publish-gridstack';
import { MutableRefObject, RefObject } from 'react';
import { AppType } from '../../../../types/app';
import { ShapeType } from '../../../../types/shape';
@@ -15,6 +15,7 @@ export const initializeGridstack = (
isEditMode: boolean,
wrapperColumnCount: 3 | 6 | 12,
shapeSize: 'sm' | 'md' | 'lg',
+ tilesWithUnknownLocation: TileWithUnknownLocation[],
events: {
onChange: (changedNode: GridStackNode) => void;
onAdd: (addedNode: GridStackNode) => void;
@@ -68,11 +69,25 @@ export const initializeGridstack = (
const item = itemRefs.current[id]?.current;
setAttributesFromShape(item, shape[shapeSize]);
item && grid.makeWidget(item as HTMLDivElement);
+ if (!shape[shapeSize] && item) {
+ const gridItemElement = item as GridItemHTMLElement;
+ if (gridItemElement.gridstackNode) {
+ const { x, y, w, h } = gridItemElement.gridstackNode;
+ tilesWithUnknownLocation.push({ x, y, w, h, type: 'app', id });
+ }
+ }
});
widgets.forEach(({ id, shape }) => {
const item = itemRefs.current[id]?.current;
setAttributesFromShape(item, shape[shapeSize]);
item && grid.makeWidget(item as HTMLDivElement);
+ if (!shape[shapeSize] && item) {
+ const gridItemElement = item as GridItemHTMLElement;
+ if (gridItemElement.gridstackNode) {
+ const { x, y, w, h } = gridItemElement.gridstackNode;
+ tilesWithUnknownLocation.push({ x, y, w, h, type: 'widget', id });
+ }
+ }
});
grid.batchUpdate(false);
};
@@ -84,3 +99,12 @@ function setAttributesFromShape(ref: HTMLDivElement | null, sizedShape: ShapeTyp
ref.setAttribute('gs-w', sizedShape.size.width.toString());
ref.setAttribute('gs-h', sizedShape.size.height.toString());
}
+
+export type TileWithUnknownLocation = {
+ x?: number;
+ y?: number;
+ w?: number;
+ h?: number;
+ type: 'app' | 'widget';
+ id: string;
+};
diff --git a/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts b/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts
index 5c401f5ac..8a87cca8a 100644
--- a/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts
+++ b/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts
@@ -6,7 +6,7 @@ import { AppType } from '../../../../types/app';
import { AreaType } from '../../../../types/area';
import { IWidget } from '../../../../widgets/widgets';
import { useEditModeStore } from '../../Views/useEditModeStore';
-import { initializeGridstack } from './init-gridstack';
+import { initializeGridstack, TileWithUnknownLocation } from './init-gridstack';
import { useGridstackStore, useWrapperColumnCount } from './store';
interface UseGristackReturnType {
@@ -232,6 +232,7 @@ export const useGridstack = (
// initialize the gridstack
useEffect(() => {
+ const tilesWithUnknownLocation: TileWithUnknownLocation[] = [];
initializeGridstack(
areaType,
wrapperRef,
@@ -243,11 +244,62 @@ export const useGridstack = (
isEditMode,
wrapperColumnCount,
shapeSize,
+ tilesWithUnknownLocation,
{
onChange,
onAdd,
}
);
+ if (!configName) return;
+ updateConfig(configName, (prev) => ({
+ ...prev,
+ apps: prev.apps.map((app) => {
+ const currentUnknownLocation = tilesWithUnknownLocation.find(
+ (x) => x.type === 'app' && x.id === app.id
+ );
+ if (!currentUnknownLocation) return app;
+
+ return {
+ ...app,
+ shape: {
+ ...app.shape,
+ [shapeSize]: {
+ location: {
+ x: currentUnknownLocation.x,
+ y: currentUnknownLocation.y,
+ },
+ size: {
+ width: currentUnknownLocation.w,
+ height: currentUnknownLocation.h,
+ },
+ },
+ },
+ };
+ }),
+ widgets: prev.widgets.map((widget) => {
+ const currentUnknownLocation = tilesWithUnknownLocation.find(
+ (x) => x.type === 'widget' && x.id === widget.id
+ );
+ if (!currentUnknownLocation) return widget;
+
+ return {
+ ...widget,
+ shape: {
+ ...widget.shape,
+ [shapeSize]: {
+ location: {
+ x: currentUnknownLocation.x,
+ y: currentUnknownLocation.y,
+ },
+ size: {
+ width: currentUnknownLocation.w,
+ height: currentUnknownLocation.h,
+ },
+ },
+ },
+ };
+ }),
+ }));
}, [items, wrapperRef.current, widgets, wrapperColumnCount]);
return {
diff --git a/src/components/layout/header/Actions/ToggleEditMode/ToggleEditMode.tsx b/src/components/layout/header/Actions/ToggleEditMode/ToggleEditMode.tsx
index 72ac9922d..a4b7a8df5 100644
--- a/src/components/layout/header/Actions/ToggleEditMode/ToggleEditMode.tsx
+++ b/src/components/layout/header/Actions/ToggleEditMode/ToggleEditMode.tsx
@@ -20,16 +20,14 @@ export const ToggleEditModeAction = () => {
const smallerThanSm = useScreenSmallerThan('sm');
const { config } = useConfigContext();
- useEffect(() => {
- if (enabled || config === undefined || config?.schemaVersion === undefined) return;
- const configName = getCookie('config-name')?.toString() ?? 'default';
- axios.put(`/api/configs/${configName}`, { ...config });
- Consola.log('Saved config to server', configName);
- }, [enabled]);
-
const toggleButtonClicked = () => {
toggleEditMode();
- if (!enabled) {
+ if (enabled || config === undefined || config?.schemaVersion === undefined) {
+ const configName = getCookie('config-name')?.toString() ?? 'default';
+ axios.put(`/api/configs/${configName}`, { ...config });
+ Consola.log('Saved config to server', configName);
+ hideNotification('toggle-edit-mode');
+ } else if (!enabled) {
showNotification({
styles: (theme) => ({
root: {
diff --git a/src/modules/Docker/ContainerActionBar.tsx b/src/modules/Docker/ContainerActionBar.tsx
index da7388c73..9036fce07 100644
--- a/src/modules/Docker/ContainerActionBar.tsx
+++ b/src/modules/Docker/ContainerActionBar.tsx
@@ -189,38 +189,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
id: getLowestWrapper()?.id ?? 'default',
},
},
- shape: {
- sm: {
- location: {
- x: 0,
- y: 0,
- },
- size: {
- width: appTileDefinition.minWidth,
- height: appTileDefinition.minHeight,
- },
- },
- md: {
- location: {
- x: 0,
- y: 0,
- },
- size: {
- width: appTileDefinition.minWidth,
- height: appTileDefinition.minHeight,
- },
- },
- lg: {
- location: {
- x: 0,
- y: 0,
- },
- size: {
- width: appTileDefinition.minWidth,
- height: appTileDefinition.minHeight,
- },
- },
- },
+ shape: {},
integration: {
type: null,
properties: [],
diff --git a/src/tools/config/migrateConfig.ts b/src/tools/config/migrateConfig.ts
index a98e5dd29..11cbe9c8b 100644
--- a/src/tools/config/migrateConfig.ts
+++ b/src/tools/config/migrateConfig.ts
@@ -34,9 +34,9 @@ export function migrateConfig(config: Config): ConfigType {
},
customization: {
colors: {
- primary: config.settings.primaryColor,
- secondary: config.settings.secondaryColor,
- shade: config.settings.primaryShade,
+ primary: config.settings.primaryColor ?? 'red',
+ secondary: config.settings.secondaryColor ?? 'orange',
+ shade: config.settings.primaryShade ?? 7,
},
layout: {
enabledDocker: config.modules.docker?.enabled ?? false,
@@ -60,7 +60,7 @@ export function migrateConfig(config: Config): ConfigType {
if (!categoryName) {
newConfig.apps.push(
- migrateService(service, index, {
+ migrateService(service, {
type: 'wrapper',
properties: {
id: 'default',
@@ -77,7 +77,7 @@ export function migrateConfig(config: Config): ConfigType {
}
newConfig.apps.push(
- migrateService(service, index, { type: 'category', properties: { id: category.id } })
+ migrateService(service, { type: 'category', properties: { id: category.id } })
);
});
@@ -114,11 +114,7 @@ const getShapeForColumnCount = (index: number, columnCount: number) => ({
},
});
-const migrateService = (
- oldService: serviceItem,
- serviceIndex: number,
- areaType: AreaType
-): AppType => ({
+const migrateService = (oldService: serviceItem, areaType: AreaType): AppType => ({
id: uuidv4(),
name: oldService.name,
url: oldService.url,
@@ -135,11 +131,7 @@ const migrateService = (
},
integration: migrateIntegration(oldService),
area: areaType,
- shape: {
- lg: getShapeForColumnCount(serviceIndex, 12),
- md: getShapeForColumnCount(serviceIndex, 6),
- sm: getShapeForColumnCount(serviceIndex, 3),
- },
+ shape: {},
});
const migrateModules = (config: Config): IWidget[] => {