new controllers for components and layouts

This commit is contained in:
arpitnath 2023-08-13 01:42:56 +05:30
parent ec58c5cbd0
commit 08274d53ff
12 changed files with 130 additions and 41 deletions

View file

@ -60,8 +60,6 @@ export const Container = ({
[JSON.stringify(appDefinition), currentPageId]
);
console.log('----mohaaan components', { components });
const currentState = useCurrentState();
const { appVersionsId, enableReleasedVersionPopupState, isVersionReleased } = useAppVersionStore(
(state) => ({
@ -149,6 +147,7 @@ export const Container = ({
const noOfBoxs = Object.values(boxes || []).length;
useEffect(() => {
updateCanvasHeight(boxes);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [noOfBoxs]);
const moveBox = useCallback(

View file

@ -64,9 +64,10 @@ import { shallow } from 'zustand/shallow';
import { useEditorActions, useEditorState, useEditorStore } from '@/_stores/editorStore';
import { useAppDataActions, useAppDataStore, useAppInfo } from '@/_stores/appDataStore';
import { useMounted } from '@/_hooks/use-mount';
// eslint-disable-next-line import/no-unresolved
import { diff } from 'deep-object-diff';
import { camelizeKeys } from 'humps';
import { camelizeKeys, decamelizeKeys } from 'humps';
setAutoFreeze(false);
enablePatches();
@ -227,7 +228,6 @@ const EditorComponent = (props) => {
}
if (mounted && didAppDefinitionChanged && currentPageId) {
console.log('----mohaaan: useEffecr', { appDefinition });
const components = appDefinition?.pages[currentPageId]?.components || {};
computeComponentState(components);
@ -236,6 +236,7 @@ const EditorComponent = (props) => {
autoSave();
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify({ appDefinition, currentPageId, dataQueries })]);
const editorRef = {
@ -630,6 +631,47 @@ const EditorComponent = (props) => {
};
//!--------
const buildComponentMetaDefinition = (components = {}) => {
for (const componentId in components) {
const currentComponentData = components[componentId];
const componentMeta = componentTypes.find((comp) => currentComponentData.component.component === comp.component);
const mergedDefinition = {
...componentMeta.definition,
properties: {
...componentMeta.definition.properties,
...currentComponentData?.component.definition.properties,
},
styles: {
...componentMeta.definition.styles,
...currentComponentData?.component.definition.styles,
},
validations: {
...componentMeta.definition.validations,
...currentComponentData?.component.definition.validations,
},
};
const mergedComponent = {
component: {
...componentMeta,
...currentComponentData.component,
},
layouts: {
...currentComponentData.layouts,
},
withDefaultChildren: componentMeta.withDefaultChildren ?? false,
};
mergedComponent.component.definition = mergedDefinition;
components[componentId] = mergedComponent;
}
return components;
};
const buildAppDefinition = (data) => {
const editingVersion = _.omit(camelizeKeys(data.editing_version), ['definition', 'updatedAt', 'createdAt', 'name']);
@ -637,6 +679,10 @@ const EditorComponent = (props) => {
_.unset(editingVersion, 'id');
const pages = data.pages.reduce((acc, page) => {
const currentComponents = buildComponentMetaDefinition(_.cloneDeep(page?.components));
page.components = currentComponents;
acc[page.id] = page;
return acc;
@ -649,6 +695,8 @@ const EditorComponent = (props) => {
pages: pages,
};
// const componentMeta = componentTypes.find((comp) => component.component === comp.component);
return appJSON;
};
@ -677,7 +725,7 @@ const EditorComponent = (props) => {
const homePageId = !startingPageId || startingPageId === 'null' ? appJson.homePageId : startingPageId;
const currentComponents = appJson.pages[homePageId]?.components ?? {};
console.log('---piku [fetching app] [pages] ==> ', { currentComponents });
console.log('---arpit [fetching app] [pages] ==> ', { currentComponents });
const currentpageData = {
handle: appJson.pages[homePageId]?.handle,
name: appJson.pages[homePageId]?.name,
@ -727,7 +775,6 @@ const EditorComponent = (props) => {
// !--------
const setAppDefinitionFromVersion = (version, shouldWeEditVersion = true) => {
console.log('---arpit [setAppFromVersion]--', version);
if (version?.id !== props.editingVersion?.id) {
appDefinitionChanged(defaults(version.definition, defaultDefinition(props.darkMode)), {
skipAutoSave: true,
@ -783,11 +830,6 @@ const EditorComponent = (props) => {
let updatedAppDefinition;
const copyOfAppDefinition = JSON.parse(JSON.stringify(appDefinition));
console.log('--arpit | appDefinitionChanged func()', {
opts,
newDefinition,
});
updatedAppDefinition = produce(copyOfAppDefinition, (draft) => {
if (_.isEmpty(draft)) return;
@ -822,6 +864,7 @@ const EditorComponent = (props) => {
setUndoStack((prev) => [...prev, undoPatches]);
updateAppDefinitionDiff(diffPatches);
updateState({
appDiffOptions: opts,
});
@ -839,7 +882,6 @@ const EditorComponent = (props) => {
};
const saveEditingVersion = (isUserSwitchedVersion = false) => {
console.log('---arpit [saving - editionversion]--', { appDefinitionDiff });
if (props.isVersionReleased && !isUserSwitchedVersion) {
updateEditorState({
isSaving: false,
@ -952,10 +994,10 @@ const EditorComponent = (props) => {
canUndo: undoStack.length > 0,
canRedo: redoStack.length > 0,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(undoStack), JSON.stringify(redoStack)]);
const componentDefinitionChanged = (componentDefinition, props) => {
console.log('---arpit checking:::: ', { props });
if (props?.isVersionReleased) {
useAppVersionStore.getState().actions.enableReleasedVersionPopupState();
return;
@ -1024,6 +1066,7 @@ const EditorComponent = (props) => {
}
appDefinitionChanged(newDefinition, {
componentDefinitionChanged: true,
componentDeleted: true,
});
handleInspectorView();
} else {

View file

@ -10,7 +10,6 @@ export const EditorKeyHooks = ({
removeMultipleComponents,
}) => {
const handleHotKeysCallback = (key) => {
console.log('---arpit-- hotkeys', { key });
switch (key) {
case 'Escape':
handleEditorEscapeKeyPress();
@ -19,7 +18,6 @@ export const EditorKeyHooks = ({
removeMultipleComponents();
break;
case 'KeyD':
console.log('---arpit-- paste component');
cloneComponents();
break;
case 'KeyC':

View file

@ -1130,10 +1130,11 @@ export function renderTooltip({ props, text }) {
export function computeComponentState(components = {}) {
let componentState = {};
const currentComponents = getCurrentState().components;
Object.keys(components).forEach((key) => {
const component = components[key];
const componentMeta = componentTypes.find((comp) => component.component.component === comp.component);
console.log('------tj: computeComponentState', { component, currentComponents });
const { component } = components[key];
const componentMeta = componentTypes.find((comp) => component.component === comp.component);
const existingComponentName = Object.keys(currentComponents).find((comp) => currentComponents[comp].id === key);
const existingValues = currentComponents[existingComponentName];
@ -1149,14 +1150,14 @@ export function computeComponentState(components = {}) {
}
if (!isListView && !isForm) {
componentState[component.component.name] = {
componentState[component.name] = {
...componentMeta.exposedVariables,
id: key,
...existingValues,
};
}
} else {
componentState[component.component.name] = {
componentState[component.name] = {
...componentMeta.exposedVariables,
id: key,
...existingValues,
@ -1586,7 +1587,7 @@ export const removeSelectedComponent = (pageId, newDefinition, selectedComponent
delete newDefinition.pages[pageId].components[component.id];
});
updateAppDefinition(newDefinition, { componentDefinitionChanged: true });
updateAppDefinition(newDefinition, { componentDefinitionChanged: true, componentDeleted: true });
};
const getSelectedText = () => {

View file

@ -60,8 +60,6 @@ function save(appId, versionId, values, isUserSwitchedVersion = false) {
return fetch(`${config.apiUrl}/apps/${appId}/versions/${versionId}`, requestOptions).then(handleResponse);
}
function autoSaveApp(appId, versionId, diff, type, pageId, operation, isUserSwitchedVersion = false) {
console.log('---piku [version saved] [v2]', { operation, type, diff });
const OPERATION = Object.freeze({
create: 'POST',
update: 'PUT',

View file

@ -32,7 +32,6 @@ export const useAppDataStore = create(
updateState: (state) => set((prev) => ({ ...prev, ...state })),
updateAppDefinitionDiff: (appDefinitionDiff) => set(() => ({ appDefinitionDiff: appDefinitionDiff })),
updateAppVersion: async (appId, versionId, pageId, appDefinitionDiff, isUserSwitchedVersion = false) => {
// console.log('-piku :: from store', { appDefinitionDiff });
return await appVersionService.autoSaveApp(
appId,
versionId,

View file

@ -32,6 +32,7 @@ const defaultComponent = {
styles: {},
validation: {},
events: [],
type: '',
};
const updateType = Object.freeze({
@ -39,6 +40,7 @@ const updateType = Object.freeze({
containerChanges: 'components/layout',
componentAdded: 'components',
componentDefinitionChanged: 'components',
componentDeleted: 'components',
});
export const computeAppDiff = (appDiff, currentPageId, opts) => {
@ -46,10 +48,20 @@ export const computeAppDiff = (appDiff, currentPageId, opts) => {
let updateDiff;
let operation = 'update';
console.log('---piku [computeAppDiff]', { appDiff, currentPageId, opts });
if (opts?.pageDefinitionChanged) {
updateDiff = appDiff?.pages[currentPageId];
type = updateType.pageDefinitionChanged;
} else if (opts?.componentDeleted) {
const currentPageComponents = appDiff?.pages[currentPageId]?.components;
updateDiff = _.keys(currentPageComponents);
type = updateType.componentDeleted;
operation = 'delete';
} else if ((opts?.containerChanges || opts?.componentDefinitionChanged) && !opts?.componentAdded) {
const currentPageComponents = appDiff?.pages[currentPageId]?.components;
@ -65,16 +77,15 @@ export const computeAppDiff = (appDiff, currentPageId, opts) => {
result[id] = _.defaultsDeep(metaDiff, defaultComponent);
result[id].type = componentMeta.component;
result[id].layouts = appDiff.pages[currentPageId].components[id].layouts;
operation = 'create';
return result;
}, {});
type = updateType.componentDefinitionChanged;
}
console.log('---piku [currentPageComponents]', { updateDiff, opts, type });
return { updateDiff, type, operation };
};

View file

@ -17,6 +17,11 @@ export class CreateComponentTable1691006952074 implements MigrationInterface {
type: 'varchar',
isNullable: false,
},
{
name: 'type',
type: 'varchar',
isNullable: false,
},
{
name: 'page_id',
type: 'uuid',

View file

@ -101,7 +101,7 @@ export class AppsController {
response['data_queries'] = seralizedQueries;
response['definition'] = app.editingVersion?.definition;
response['pages'] = decamelizeKeys(pagesForVersion);
response['pages'] = pagesForVersion;
//! if editing version exists, camelize the definition
if (app.editingVersion && app.editingVersion.definition) {
@ -320,9 +320,6 @@ export class AppsController {
throw new ForbiddenException('You do not have permissions to perform this action');
}
// const updateType = versionEditDto.app_diff?.type;
// console.log('----arpit apps controller => ', { updateType });
await this.appsService.updateVersion(version, versionEditDto, app.organizationId);
return;
}
@ -347,8 +344,6 @@ export class AppsController {
throw new ForbiddenException('You do not have permissions to perform this action');
}
// const updateType = versionEditDto.app_diff?.type;
console.log('----arpit apps controller v2 => ', { versionEditDto });
await this.componentsService.create(versionEditDto.diff, versionEditDto.pageId);
}
@UseGuards(JwtAuthGuard)
@ -372,10 +367,33 @@ export class AppsController {
throw new ForbiddenException('You do not have permissions to perform this action');
}
// const updateType = versionEditDto.app_diff?.type;
console.log('----arpit apps controller v2 [update] => ', { versionEditDto });
await this.componentsService.update(versionEditDto.diff);
}
@UseGuards(JwtAuthGuard)
@UseInterceptors(ValidAppInterceptor)
@Delete(':id/versions/:versionId/components')
async deleteComponents(
@User() user,
@Param('id') id,
@Param('versionId') versionId,
@Body() versionEditDto: VersionEditDto
) {
const version = await this.appsService.findVersion(versionId);
const app = version.app;
if (app.id !== id) {
throw new BadRequestException();
}
const ability = await this.appsAbilityFactory.appsActions(user, id);
if (!ability.can('updateVersions', app)) {
throw new ForbiddenException('You do not have permissions to perform this action');
}
await this.componentsService.delete(versionEditDto.diff);
}
@UseGuards(JwtAuthGuard)
@UseInterceptors(ValidAppInterceptor)
@Put(':id/versions/:versionId/components/layout')
@ -397,8 +415,6 @@ export class AppsController {
throw new ForbiddenException('You do not have permissions to perform this action');
}
// const updateType = versionEditDto.app_diff?.type;
console.log('----arpit apps controller v2 |layput | [update] => ', { versionEditDto });
await this.componentsService.componentLayoutChange(versionEditDto.diff);
}

View file

@ -10,6 +10,9 @@ export class Component {
@Column({ name: 'name' })
name: string;
@Column({ name: 'type' })
type: string;
@Column({ name: 'page_id' })
pageId: string;

View file

@ -122,8 +122,8 @@ export class AppsService {
const defaultHomePage = await manager.save(
manager.create(Page, {
name: 'Home',
pageHandle: 'home',
name: 'Defualt Page',
pageHandle: 'defaultpage',
appVersionId: appVersion.id,
})
);

View file

@ -97,6 +97,22 @@ export class ComponentsService {
});
}
async delete(componentIds: string[]) {
return dbTransactionWrap(async (manager: EntityManager) => {
const components = await manager.findByIds(Component, componentIds);
if (!components.length) {
return {
error: {
message: `Components with ids ${componentIds} do not exist`,
},
};
}
await manager.delete(Component, componentIds);
});
}
async componentLayoutChange(componenstLayoutDiff: object) {
return dbTransactionWrap(async (manager: EntityManager) => {
for (const componentId in componenstLayoutDiff) {
@ -124,8 +140,6 @@ export class ComponentsService {
...layout,
};
console.log('--arpit [layput changed]', { type, layout, componentLayout, newLayout });
await manager.update(Layout, { id: componentLayout.id }, newLayout);
}
}
@ -166,6 +180,7 @@ export class ComponentsService {
const transformedComponent: Component = new Component();
transformedComponent.id = componentId;
transformedComponent.name = componentData.name;
transformedComponent.type = componentData.type;
transformedComponent.properties = componentData.properties || {};
transformedComponent.styles = componentData.styles || {};
transformedComponent.validations = componentData.validation || {};
@ -184,6 +199,7 @@ export class ComponentsService {
[id]: {
component: {
name,
component: componentData.type,
definition: {
properties,
styles,