🐛 Fix issues with gridstack

This commit is contained in:
Meierschlumpf
2023-01-07 23:25:13 +01:00
parent 5585d9e678
commit d886bbdaad
8 changed files with 139 additions and 113 deletions

View File

@@ -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: [],

View File

@@ -1,5 +1,6 @@
/* eslint-disable react/no-unknown-property */
import { ReactNode, RefObject } from 'react';
import widgets from '../../../widgets';
interface GridstackTileWrapperProps {
id: string;
@@ -29,19 +30,22 @@ export const GridstackTileWrapper = ({
maxHeight,
children,
itemRef,
}: GridstackTileWrapperProps) => (
}: GridstackTileWrapperProps) => {
const locationProperties = useLocationProperties(x, y);
const normalizedWidth = width ?? minWidth;
const normalizedHeight = height ?? minHeight;
return (
<div
className="grid-stack-item"
data-type={type}
data-id={id}
gs-x={x}
data-gridstack-x={x}
gs-y={y}
data-gridstack-y={y}
gs-w={width}
data-gridstack-w={width}
gs-h={height}
data-gridstack-h={height}
{...locationProperties}
gs-w={normalizedWidth}
data-gridstack-w={normalizedWidth}
gs-h={normalizedHeight}
data-gridstack-h={normalizedHeight}
gs-min-w={minWidth}
gs-min-h={minHeight}
gs-max-w={maxWidth}
@@ -51,3 +55,21 @@ export const GridstackTileWrapper = ({
{children}
</div>
);
};
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(),
};
};

View File

@@ -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 ?? {})}
>
<TileComponent className="grid-stack-item-content" app={app} />
</GridstackTileWrapper>

View File

@@ -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;
};

View File

@@ -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 {

View File

@@ -20,16 +20,14 @@ export const ToggleEditModeAction = () => {
const smallerThanSm = useScreenSmallerThan('sm');
const { config } = useConfigContext();
useEffect(() => {
if (enabled || config === undefined || config?.schemaVersion === undefined) return;
const toggleButtonClicked = () => {
toggleEditMode();
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);
}, [enabled]);
const toggleButtonClicked = () => {
toggleEditMode();
if (!enabled) {
hideNotification('toggle-edit-mode');
} else if (!enabled) {
showNotification({
styles: (theme) => ({
root: {

View File

@@ -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: [],

View File

@@ -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<string, any>[] => {